Skip to content

Commit

Permalink
test: Add test to call async callback (#433)
Browse files Browse the repository at this point in the history
* test: Add test to call async callback

* feat: Test `callbackAsyncPromise()`

* Update getTests.ts

* fix tests

* Update NitroImage-Swift-Cxx-Bridge.hpp

* fix: Gen specs
  • Loading branch information
mrousavy authored Dec 20, 2024
1 parent 699e138 commit d0067b2
Show file tree
Hide file tree
Showing 23 changed files with 469 additions and 10 deletions.
40 changes: 30 additions & 10 deletions example/src/getTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -851,12 +851,14 @@ export function getTests(
.didNotThrow()
.equals('hello')
),
createTest('getValueFromJSCallbackAndWait(...)', async () =>
(await it(() => testObject.getValueFromJSCallbackAndWait(() => 73)))
.didNotThrow()
.equals(73)
),
createTest('callAll(...)', async () =>
createTest(
'Single callback can be called and awaited: getValueFromJSCallbackAndWait(...)',
async () =>
(await it(() => testObject.getValueFromJSCallbackAndWait(() => 73)))
.didNotThrow()
.equals(73)
),
createTest('Multiple callbacks are all called: callAll(...)', async () =>
(
await it(async () => {
return timeoutedPromise((complete) => {
Expand All @@ -872,10 +874,28 @@ export function getTests(
.didNotThrow()
.equals(3)
),
createTest('callSumUpNTimes(...)', async () =>
(await it(async () => await testObject.callSumUpNTimes(() => 7, 5)))
.didNotThrow()
.equals(7 * 5 /* = 35 */)
createTest(
'Callback can be called multiple times: callSumUpNTimes(...)',
async () =>
(await it(async () => await testObject.callSumUpNTimes(() => 7, 5)))
.didNotThrow()
.equals(7 * 5 /* = 35 */)
),
createTest(
'Async callback can be awaited and returned on native side: callbackAsyncPromise(...)',
async () =>
(
await it(async () => {
return timeoutedPromise(async (complete) => {
const result = await testObject.callbackAsyncPromise(async () => {
return 13
})
complete(result)
})
})
)
.didNotThrow()
.equals(13)
),

// Objects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ class HybridTestObjectKotlin: HybridTestObjectSwiftKotlinSpec() {
}
}

override fun callbackAsyncPromise(callback: () -> Promise<Promise<Double>>): Promise<Double> {
return Promise.async {
val promise = callback().await()
val result = promise.await()
return@async result
}
}

override fun getCar(): Car {
return Car(2018.0, "Lamborghini", "Huracán", 640.0, Powertrain.GAS, null, true)
}
Expand Down
11 changes: 11 additions & 0 deletions packages/react-native-nitro-image/cpp/HybridTestObjectCpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,17 @@ std::shared_ptr<Promise<double>> HybridTestObjectCpp::callSumUpNTimes(const std:
});
}

std::shared_ptr<Promise<double>>
HybridTestObjectCpp::callbackAsyncPromise(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>& callback) {
return Promise<double>::async([=]() {
std::future<std::shared_ptr<Promise<double>>> future = callback()->await();
std::shared_ptr<Promise<double>> promise = future.get();
std::future<double> innerFuture = promise->await();
double innerResult = innerFuture.get();
return innerResult;
});
}

std::shared_ptr<Promise<double>>
HybridTestObjectCpp::getValueFromJSCallbackAndWait(const std::function<std::shared_ptr<Promise<double>>()>& getValue) {
return Promise<double>::async([=]() -> double {
Expand Down
2 changes: 2 additions & 0 deletions packages/react-native-nitro-image/cpp/HybridTestObjectCpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ class HybridTestObjectCpp : public HybridTestObjectCppSpec {
getValueFromJSCallbackAndWait(const std::function<std::shared_ptr<Promise<double>>()>& getValue) override;
void callAll(const std::function<void()>& first, const std::function<void()>& second, const std::function<void()>& third) override;
std::shared_ptr<Promise<double>> callSumUpNTimes(const std::function<std::shared_ptr<Promise<double>>()>& callback, double n) override;
std::shared_ptr<Promise<double>>
callbackAsyncPromise(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>& callback) override;
std::shared_ptr<Promise<void>>
getValueFromJsCallback(const std::function<std::shared_ptr<Promise<std::string>>()>& callback,
const std::function<void(const std::string& /* valueFromJs */)>& andThenCall) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ class HybridTestObjectSwift : HybridTestObjectSwiftKotlinSpec {
}
}

func callbackAsyncPromise(callback: @escaping (() -> Promise<Promise<Double>>)) throws -> Promise<Double> {
return Promise.async {
let promise = try await callback().await()
let result = try await promise.await()
return result
}
}


func bounceStrings(array: [String]) throws -> [String] {
return array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "JFunc_void.hpp"
#include "JFunc_void_std__optional_double_.hpp"
#include "JFunc_std__shared_ptr_Promise_double__.hpp"
#include "JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____.hpp"
#include "JFunc_std__shared_ptr_Promise_std__string__.hpp"
#include "JHybridBaseSpec.hpp"
#include "JHybridChildSpec.hpp"
Expand Down Expand Up @@ -46,6 +47,7 @@ int initialize(JavaVM* vm) {
margelo::nitro::image::JFunc_void::registerNatives();
margelo::nitro::image::JFunc_void_std__optional_double_::registerNatives();
margelo::nitro::image::JFunc_std__shared_ptr_Promise_double__::registerNatives();
margelo::nitro::image::JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::registerNatives();
margelo::nitro::image::JFunc_std__shared_ptr_Promise_double__::registerNatives();
margelo::nitro::image::JFunc_std__shared_ptr_Promise_std__string__::registerNatives();
margelo::nitro::image::JFunc_void_std__string::registerNatives();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
///
/// JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____.hpp
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2024 Marc Rousavy @ Margelo
///

#pragma once

#include <fbjni/fbjni.h>
#include <functional>

#include <functional>
#include <NitroModules/Promise.hpp>
#include <NitroModules/JPromise.hpp>

namespace margelo::nitro::image {

using namespace facebook;

/**
* C++ representation of the callback Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____.
* This is a Kotlin `() -> Promise<Promise<Double>>`, backed by a `std::function<...>`.
*/
struct JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____ final: public jni::HybridClass<JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____> {
public:
static jni::local_ref<JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::javaobject> fromCpp(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>& func) {
return JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::newObjectCxxArgs(func);
}

public:
jni::local_ref<JPromise::javaobject> call() {
std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>> __result = _func();
return [&]() {
jni::local_ref<JPromise::javaobject> __localPromise = JPromise::create();
jni::global_ref<JPromise::javaobject> __promise = jni::make_global(__localPromise);
__result->addOnResolvedListener([=](const std::shared_ptr<Promise<double>>& __result) {
__promise->cthis()->resolve([&]() {
jni::local_ref<JPromise::javaobject> __localPromise = JPromise::create();
jni::global_ref<JPromise::javaobject> __promise = jni::make_global(__localPromise);
__result->addOnResolvedListener([=](const double& __result) {
__promise->cthis()->resolve(jni::JDouble::valueOf(__result));
});
__result->addOnRejectedListener([=](const std::exception_ptr& __error) {
auto __jniError = jni::getJavaExceptionForCppException(__error);
__promise->cthis()->reject(__jniError);
});
return __localPromise;
}());
});
__result->addOnRejectedListener([=](const std::exception_ptr& __error) {
auto __jniError = jni::getJavaExceptionForCppException(__error);
__promise->cthis()->reject(__jniError);
});
return __localPromise;
}();
}

public:
static auto constexpr kJavaDescriptor = "Lcom/margelo/nitro/image/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____;";
static void registerNatives() {
registerHybrid({makeNativeMethod("call", JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::call)});
}

private:
explicit JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>& func): _func(func) { }

private:
friend HybridBase;
std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()> _func;
};

} // namespace margelo::nitro::image
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace margelo::nitro::image { class HybridBaseSpec; }
#include "JFunc_void.hpp"
#include "JFunc_void_std__optional_double_.hpp"
#include "JFunc_std__shared_ptr_Promise_double__.hpp"
#include "JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____.hpp"
#include "JFunc_std__shared_ptr_Promise_std__string__.hpp"
#include "JFunc_void_std__string.hpp"

Expand Down Expand Up @@ -537,6 +538,22 @@ namespace margelo::nitro::image {
return __promise;
}();
}
std::shared_ptr<Promise<double>> JHybridTestObjectSwiftKotlinSpec::callbackAsyncPromise(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>& callback) {
static const auto method = _javaPart->getClass()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::javaobject> /* callback */)>("callbackAsyncPromise");
auto __result = method(_javaPart, JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::fromCpp(callback));
return [&]() {
auto __promise = Promise<double>::create();
__result->cthis()->addOnResolvedListener([=](const jni::alias_ref<jni::JObject>& __boxedResult) {
auto __result = jni::static_ref_cast<jni::JDouble>(__boxedResult);
__promise->resolve(__result->value());
});
__result->cthis()->addOnRejectedListener([=](const jni::alias_ref<jni::JThrowable>& __throwable) {
jni::JniException __jniError(__throwable);
__promise->reject(std::make_exception_ptr(__jniError));
});
return __promise;
}();
}
std::shared_ptr<Promise<double>> JHybridTestObjectSwiftKotlinSpec::getValueFromJSCallbackAndWait(const std::function<std::shared_ptr<Promise<double>>()>& getValue) {
static const auto method = _javaPart->getClass()->getMethod<jni::local_ref<JPromise::javaobject>(jni::alias_ref<JFunc_std__shared_ptr_Promise_double__::javaobject> /* getValue */)>("getValueFromJSCallbackAndWait");
auto __result = method(_javaPart, JFunc_std__shared_ptr_Promise_double__::fromCpp(getValue));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ namespace margelo::nitro::image {
void callAll(const std::function<void()>& first, const std::function<void()>& second, const std::function<void()>& third) override;
void callWithOptional(std::optional<double> value, const std::function<void(std::optional<double> /* maybe */)>& callback) override;
std::shared_ptr<Promise<double>> callSumUpNTimes(const std::function<std::shared_ptr<Promise<double>>()>& callback, double n) override;
std::shared_ptr<Promise<double>> callbackAsyncPromise(const std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>& callback) override;
std::shared_ptr<Promise<double>> getValueFromJSCallbackAndWait(const std::function<std::shared_ptr<Promise<double>>()>& getValue) override;
std::shared_ptr<Promise<void>> getValueFromJsCallback(const std::function<std::shared_ptr<Promise<std::string>>()>& callback, const std::function<void(const std::string& /* valueFromJs */)>& andThenCall) override;
Car getCar() override;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
///
/// Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____.kt
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
/// https://github.com/mrousavy/nitro
/// Copyright © 2024 Marc Rousavy @ Margelo
///

package com.margelo.nitro.image

import androidx.annotation.Keep
import com.facebook.jni.HybridData
import com.facebook.proguard.annotations.DoNotStrip
import com.margelo.nitro.core.*
import dalvik.annotation.optimization.FastNative

/**
* Represents the JavaScript callback `() => std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>`.
* This is implemented in C++, via a `std::function<...>`.
*/
@DoNotStrip
@Keep
@Suppress("RedundantSuppression", "ConvertSecondaryConstructorToPrimary", "RedundantUnitReturnType", "KotlinJniMissingFunction", "ClassName", "unused")
class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____ {
@DoNotStrip
@Keep
private val mHybridData: HybridData

@DoNotStrip
@Keep
private constructor(hybridData: HybridData) {
mHybridData = hybridData
}

/**
* Converts this function to a Kotlin Lambda.
* This exists purely as syntactic sugar, and has minimal runtime overhead.
*/
fun toLambda(): () -> Promise<Promise<Double>> = this::call

/**
* Call the given JS callback.
* @throws Throwable if the JS function itself throws an error, or if the JS function/runtime has already been deleted.
*/
@FastNative
external fun call(): Promise<Promise<Double>>
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,17 @@ abstract class HybridTestObjectSwiftKotlinSpec: HybridObject() {
return __result
}

@DoNotStrip
@Keep
abstract fun callbackAsyncPromise(callback: () -> Promise<Promise<Double>>): Promise<Double>

@DoNotStrip
@Keep
private fun callbackAsyncPromise(callback: Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____): Promise<Double> {
val __result = callbackAsyncPromise(callback.toLambda())
return __result
}

@DoNotStrip
@Keep
abstract fun getValueFromJSCallbackAndWait(getValue: () -> Promise<Double>): Promise<Double>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,23 @@ namespace margelo::nitro::image::bridge::swift {
};
}

// pragma MARK: std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____ create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____(void* _Nonnull swiftClosureWrapper) {
auto swiftClosure = NitroImage::Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)]() mutable -> std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>> {
auto __result = swiftClosure.call();
return __result;
};
}

// pragma MARK: std::function<void(const std::shared_ptr<Promise<double>>& /* result */)>
Func_void_std__shared_ptr_Promise_double__ create_Func_void_std__shared_ptr_Promise_double__(void* _Nonnull swiftClosureWrapper) {
auto swiftClosure = NitroImage::Func_void_std__shared_ptr_Promise_double__::fromUnsafe(swiftClosureWrapper);
return [swiftClosure = std::move(swiftClosure)](const std::shared_ptr<Promise<double>>& result) mutable -> void {
swiftClosure.call(result);
};
}

// pragma MARK: std::function<std::shared_ptr<Promise<std::string>>()>
Func_std__shared_ptr_Promise_std__string__ create_Func_std__shared_ptr_Promise_std__string__(void* _Nonnull swiftClosureWrapper) {
auto swiftClosure = NitroImage::Func_std__shared_ptr_Promise_std__string__::fromUnsafe(swiftClosureWrapper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,63 @@ namespace margelo::nitro::image::bridge::swift {
return Func_std__shared_ptr_Promise_double___Wrapper(std::move(value));
}

// pragma MARK: std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>
/**
* Specialized version of `std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>`.
*/
using Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____ = std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>;
/**
* Wrapper class for a `std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>`, this can be used from Swift.
*/
class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double_____Wrapper final {
public:
explicit Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double_____Wrapper(std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>&& func): _function(std::make_shared<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>>(std::move(func))) {}
inline std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>> call() const {
auto __result = _function->operator()();
return __result;
}
private:
std::shared_ptr<std::function<std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>()>> _function;
};
Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____ create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____(void* _Nonnull swiftClosureWrapper);
inline Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double_____Wrapper wrap_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____(Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double____ value) {
return Func_std__shared_ptr_Promise_std__shared_ptr_Promise_double_____Wrapper(std::move(value));
}

// pragma MARK: std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>
/**
* Specialized version of `std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>`.
*/
using std__shared_ptr_Promise_std__shared_ptr_Promise_double____ = std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>>;
inline std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>> create_std__shared_ptr_Promise_std__shared_ptr_Promise_double____() {
return Promise<std::shared_ptr<Promise<double>>>::create();
}
inline PromiseHolder<std::shared_ptr<Promise<double>>> wrap_std__shared_ptr_Promise_std__shared_ptr_Promise_double____(std::shared_ptr<Promise<std::shared_ptr<Promise<double>>>> promise) {
return PromiseHolder<std::shared_ptr<Promise<double>>>(std::move(promise));
}

// pragma MARK: std::function<void(const std::shared_ptr<Promise<double>>& /* result */)>
/**
* Specialized version of `std::function<void(const std::shared_ptr<Promise<double>>&)>`.
*/
using Func_void_std__shared_ptr_Promise_double__ = std::function<void(const std::shared_ptr<Promise<double>>& /* result */)>;
/**
* Wrapper class for a `std::function<void(const std::shared_ptr<Promise<double>>& / * result * /)>`, this can be used from Swift.
*/
class Func_void_std__shared_ptr_Promise_double___Wrapper final {
public:
explicit Func_void_std__shared_ptr_Promise_double___Wrapper(std::function<void(const std::shared_ptr<Promise<double>>& /* result */)>&& func): _function(std::make_shared<std::function<void(const std::shared_ptr<Promise<double>>& /* result */)>>(std::move(func))) {}
inline void call(std::shared_ptr<Promise<double>> result) const {
_function->operator()(result);
}
private:
std::shared_ptr<std::function<void(const std::shared_ptr<Promise<double>>& /* result */)>> _function;
};
Func_void_std__shared_ptr_Promise_double__ create_Func_void_std__shared_ptr_Promise_double__(void* _Nonnull swiftClosureWrapper);
inline Func_void_std__shared_ptr_Promise_double___Wrapper wrap_Func_void_std__shared_ptr_Promise_double__(Func_void_std__shared_ptr_Promise_double__ value) {
return Func_void_std__shared_ptr_Promise_double___Wrapper(std::move(value));
}

// pragma MARK: std::function<std::shared_ptr<Promise<std::string>>()>
/**
* Specialized version of `std::function<std::shared_ptr<Promise<std::string>>()>`.
Expand Down
Loading

0 comments on commit d0067b2

Please sign in to comment.