diff --git a/example/.harness/crash-reports/2026-07-17T14-50-51-361Z--android--android--logcat--logcat.txt b/example/.harness/crash-reports/2026-07-17T14-50-51-361Z--android--android--logcat--logcat.txt new file mode 100644 index 0000000000..e04cc91352 --- /dev/null +++ b/example/.harness/crash-reports/2026-07-17T14-50-51-361Z--android--android--logcat--logcat.txt @@ -0,0 +1,36 @@ +--------- beginning of crash +07-17 16:50:54.323 9295 9295 E AndroidRuntime: FATAL EXCEPTION: main +07-17 16:50:54.323 9295 9295 E AndroidRuntime: Process: com.margelo.nitroexample, PID: 9295 +07-17 16:50:54.323 9295 9295 E AndroidRuntime: com.facebook.soloader.SoLoaderDSONotFoundError: couldn't find DSO to load: libreactnative.so +07-17 16:50:54.323 9295 9295 E AndroidRuntime: existing SO sources: +07-17 16:50:54.323 9295 9295 E AndroidRuntime: SoSource 0: ApplicationSoSource[DirectorySoSource[root = /data/app/~~ltrc45ffcQoMl_alJJueQw==/com.margelo.nitroexample--0m3_FOd2upKxHOUO5Z-Sg==/lib/arm64 flags = 0]] +07-17 16:50:54.323 9295 9295 E AndroidRuntime: SoSource 1: DirectApkSoSource[root = [/data/app/~~ltrc45ffcQoMl_alJJueQw==/com.margelo.nitroexample--0m3_FOd2upKxHOUO5Z-Sg==/base.apk!/lib/x86_64]] +07-17 16:50:54.323 9295 9295 E AndroidRuntime: SoSource 2: DirectorySoSource[root = /system/lib64 flags = 3] +07-17 16:50:54.323 9295 9295 E AndroidRuntime: SoSource 3: DirectorySoSource[root = /vendor/lib64 flags = 3] +07-17 16:50:54.323 9295 9295 E AndroidRuntime: Native lib dir: /data/app/~~ltrc45ffcQoMl_alJJueQw==/com.margelo.nitroexample--0m3_FOd2upKxHOUO5Z-Sg==/lib/arm64 +07-17 16:50:54.323 9295 9295 E AndroidRuntime: +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.soloader.SoLoader.doLoadLibraryBySoName(SoLoader.java:1216) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.soloader.SoLoader.loadLibraryBySoNameImpl(SoLoader.java:1078) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:943) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.soloader.SoLoader.loadLibraryOnAndroid(SoLoader.java:859) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:842) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:812) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsCxxInterop.(ReactNativeFeatureFlagsCxxInterop.kt:28) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsCxxAccessor.override(ReactNativeFeatureFlagsCxxAccessor.kt:925) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.react.internal.featureflags.ReactNativeFeatureFlags.override(ReactNativeFeatureFlags.kt:588) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load(DefaultNewArchitectureEntryPoint.kt:101) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load(DefaultNewArchitectureEntryPoint.kt:43) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative(ReactNativeApplicationEntryPoint.java:31) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.margelo.nitroexample.MainApplication.onCreate(MainApplication.kt:29) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1396) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:8365) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.app.ActivityThread.-$$Nest$mhandleBindApplication(ActivityThread.java:0) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2776) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.os.Handler.dispatchMessageImpl(Handler.java:142) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:126) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:295) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.os.Looper.loop(Looper.java:398) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:9572) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:575) +07-17 16:50:54.323 9295 9295 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:842) diff --git a/example/.harness/manifest.js b/example/.harness/manifest.js new file mode 100644 index 0000000000..566d5b75cf --- /dev/null +++ b/example/.harness/manifest.js @@ -0,0 +1,4 @@ +global.RN_HARNESS = { + appRegistryComponentName: 'NitroExample', + disableViewFlattening: false, + }; \ No newline at end of file diff --git a/example/__tests__/nitro.harness.ts b/example/__tests__/nitro.harness.ts index 16655867b9..0d790c9c8f 100644 --- a/example/__tests__/nitro.harness.ts +++ b/example/__tests__/nitro.harness.ts @@ -4,7 +4,7 @@ import type { TestObjectCpp, TestObjectSwiftKotlin, } from 'react-native-nitro-test' -import { getTests } from '../src/getTests' +import { getTests, getIssue1439Tests } from '../src/getTests' import { harnessBackend } from '../src/testing/backends/harness' function createTestRunner( @@ -32,3 +32,14 @@ const testObjectSwiftKotlin = describe('TestObject (C++)', createTestRunner(testObjectCpp)) describe('TestObject (Swift/Kotlin)', createTestRunner(testObjectSwiftKotlin)) +describe('Issue 1439', () => { + const tests = getIssue1439Tests({ backend: harnessBackend }) + for (const test of tests) { + it(test.name, async () => { + const result = await test.run() + if (result.status === 'failed') { + throw new Error(result.message) + } + }) + } +}) diff --git a/example/src/getTests.ts b/example/src/getTests.ts index a9b0199b60..4122a2d1dc 100644 --- a/example/src/getTests.ts +++ b/example/src/getTests.ts @@ -13,6 +13,7 @@ import { Base, HybridPlatformObject, HybridChild, + HybridIssue1439, } from 'react-native-nitro-test' import { type AssertionBackend, @@ -2444,3 +2445,65 @@ export function getTests( ), ] } + +/** + * Tests reproducing https://github.com/mrousavy/nitro/issues/1439 + * + * A JS async function is passed inside a struct to native code. + * Native calls it twice from a background thread — first call throws, second should succeed. + */ +export function getIssue1439Tests(options: GetTestsOptions = {}): TestRunner[] { + const backend = options.backend ?? throwingBackend + const { it } = createTestRunner(backend) + const createTest = createCreateTest() + + return [ + createTest( + '[Issue #1439] Second fn invocation succeeds when first threw', + async () => + ( + await it(async () => { + let callCount = 0 + const result = await HybridIssue1439.callFnTwiceFirstThrows({ + fn: async (input) => { + callCount++ + if (input.value === 'first') { + throw new Error('Expected error on first call') + } + return input.value + }, + }) + if (callCount !== 2) { + throw new Error( + `Expected fn to be called twice, got ${callCount}` + ) + } + return result + }) + ) + .didNotThrow() + .equals('second') + ), + createTest( + '[Issue #1439] fn in struct can be called multiple times without error', + async () => + ( + await it(async () => { + const results: string[] = [] + await HybridIssue1439.callFnTwiceFirstThrows({ + fn: async (input) => { + if (input.value === 'first') { + throw new Error('Expected error on first call') + } + results.push(input.value) + return input.value + }, + }) + return results.join(',') + }) + ) + .didNotThrow() + .equals('second') + ), + ] +} diff --git a/example/src/screens/HybridObjectTestsScreen.tsx b/example/src/screens/HybridObjectTestsScreen.tsx index efe067fd64..5235328e99 100644 --- a/example/src/screens/HybridObjectTestsScreen.tsx +++ b/example/src/screens/HybridObjectTestsScreen.tsx @@ -15,7 +15,7 @@ import { HybridChild, HybridBase, } from 'react-native-nitro-test' -import { getTests, type TestRunner } from '../getTests' +import { getTests, getIssue1439Tests, type TestRunner } from '../getTests' import { logPrototypeChain } from '../logPrototypeChain' import SegmentedControl from '@react-native-segmented-control/segmented-control' import { NitroModules } from 'react-native-nitro-modules' @@ -53,7 +53,10 @@ export function HybridObjectTestsScreen() { ] console.log(`Showing Tests for HybridObject "${selectedObject?.name}"`) const allTests = React.useMemo( - () => getTests(selectedObject ?? HybridTestObjectCpp), + () => [ + ...getTests(selectedObject ?? HybridTestObjectCpp), + ...getIssue1439Tests(), + ], [selectedObject] ) const [unfilteredTests, setTests] = React.useState(() => diff --git a/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/CustomContinuation.java b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/CustomContinuation.java new file mode 100644 index 0000000000..af2cfa6815 --- /dev/null +++ b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/CustomContinuation.java @@ -0,0 +1,59 @@ +package com.margelo.nitro.test; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +import kotlin.ResultKt; +import kotlin.coroutines.Continuation; +import kotlin.coroutines.CoroutineContext; +import kotlin.coroutines.EmptyCoroutineContext; + +/** + * Bridges a Kotlin {@code Continuation} to a Java {@link CompletableFuture}. + * + *

This is the exact pattern used in + * {@code JavaHybridAbtMobileClientSDK.java} (lines 627–641) that triggers + * https://github.com/mrousavy/nitro/issues/1439.

+ * + *

The bug: when the Kotlin {@code suspend fun await()} is called + * from Java with this continuation, and the {@code Promise} is already resolved + * by the time {@code await()} is called, Kotlin's {@code SafeContinuation} short-circuits: + * it returns the value directly from {@code await()} instead of calling + * {@link #resumeWith}. The Java caller ignores that return value, calls + * {@link CompletableFuture#get()}, and blocks forever because + * {@link #resumeWith} was never invoked.

+ */ +public class CustomContinuation implements Continuation { + + private final CompletableFuture future; + + public CustomContinuation(CompletableFuture future) { + this.future = future; + } + + @NotNull + @Override + public CoroutineContext getContext() { + return EmptyCoroutineContext.INSTANCE; + } + + /** + * Called by Kotlin's coroutine machinery when the {@code Promise} resolves or + * rejects asynchronously (i.e. after {@code await()} returned + * {@code COROUTINE_SUSPENDED}). + * + *

Not called when the Promise is already settled at the time + * {@code await()} is invoked — that is the root of the issue.

+ */ + @Override + public void resumeWith(@NotNull Object result) { + try { + ResultKt.throwOnFailure(result); + //noinspection unchecked + future.complete((T) result); + } catch (Throwable t) { + future.completeExceptionally(t); + } + } +} diff --git a/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridIssue1439.kt b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridIssue1439.kt new file mode 100644 index 0000000000..e0ba6275d4 --- /dev/null +++ b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/HybridIssue1439.kt @@ -0,0 +1,110 @@ +package com.margelo.nitro.test + +import android.util.Log +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip +import com.margelo.nitro.core.Promise +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutionException +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException + +@Keep +@DoNotStrip +class HybridIssue1439 : HybridIssue1439Spec() { + + /** + * Single-threaded executor pool — mirrors the `IdlingScheduledThreadPoolExecutor` + * used in JavaHybridAbtMobileClientSDK.java. + */ + private val executor = Executors.newSingleThreadExecutor { r -> + Thread(r, "issue1439-pool-thread-0").also { it.isDaemon = true } + } + + /** + * Reproduces https://github.com/mrousavy/nitro/issues/1439 + * + * Uses the EXACT pattern from JavaHybridAbtMobileClientSDK.java (lines 627–641): + * - A thread-pool executor (not a coroutine) + * - `call.await(new CustomContinuation<>(future))` from Java + * - `future.get()` blocking wait + * + * Root cause: when `Promise.await(continuation)` is called from Java/non-coroutine Kotlin + * and the Promise is *already resolved*, Kotlin's `SafeContinuation` returns the value + * directly from `await()` — without ever invoking `CustomContinuation.resumeWith()`. + * The Java caller ignores the return value and calls `future.get()` which blocks forever. + * + * This happens because the inner Promise (for the second `fn` invocation) can already be + * resolved by the time we call `await()` on it, depending on JS thread scheduling. + */ + override fun callFnTwiceFirstThrows(params: Issue1439Params): Promise { + val outerPromise = Promise() + + executor.submit { + try { + // First invocation — expected to throw + try { + val result = callFnBlockingJavaStyle(params.fn, Issue1439CallInput("first")) + Log.w(TAG, "First call unexpectedly succeeded with: $result") + } catch (e: Exception) { + Log.d(TAG, "First call threw as expected: ${e.message}") + } + + // Second invocation — should return "second" but hangs when inner Promise is + // already resolved and SafeContinuation returns the value without calling + // CustomContinuation.resumeWith(), leaving future2 incomplete. + Log.d(TAG, "Starting second invocation...") + val result = callFnBlockingJavaStyle(params.fn, Issue1439CallInput("second")) + Log.d(TAG, "Second call returned: $result") + outerPromise.resolve(result) + } catch (e: TimeoutException) { + val msg = "Issue #1439: second fn invocation timed out — " + + "SafeContinuation swallowed the resume, CompletableFuture.get() blocks forever" + Log.e(TAG, msg) + outerPromise.reject(RuntimeException(msg, e)) + } catch (e: Exception) { + Log.e(TAG, "callFnTwiceFirstThrows failed: ${e.message}", e) + outerPromise.reject(e) + } + } + + return outerPromise + } + + /** + * Faithfully mirrors JavaHybridAbtMobileClientSDK.java lines 627–641. + * + * The critical path that triggers the bug: + * + * ```java + * Promise> call = fn.invoke(input); + * + * CompletableFuture> future1 = new CompletableFuture<>(); + * call.await(new CustomContinuation<>(future1)); // ← Java calling a Kotlin suspend fun + * Promise inner = future1.get(); // blocks until JS dispatched + * + * CompletableFuture future2 = new CompletableFuture<>(); + * inner.await(new CustomContinuation<>(future2)); // ← BUG: if inner already resolved, + * // SafeContinuation returns value directly, + * // CustomContinuation.resumeWith never called + * String result = future2.get(); // ← hangs forever + * ``` + * + * Called from Kotlin via [JavaCallHelper] to stay on the same raw thread. + */ + @Throws(Exception::class) + private fun callFnBlockingJavaStyle( + fn: (input: Issue1439CallInput) -> Promise>, + input: Issue1439CallInput, + ): String { + val call: Promise> = fn(input) + return JavaCallHelper.awaitFnBlocking(call, TIMEOUT_SECONDS, TimeUnit.SECONDS) + } + + companion object { + private const val TAG = "HybridIssue1439" + private const val TIMEOUT_SECONDS = 3L + } +} + diff --git a/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/JavaCallHelper.java b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/JavaCallHelper.java new file mode 100644 index 0000000000..a5384e7c24 --- /dev/null +++ b/packages/react-native-nitro-test/android/src/main/java/com/margelo/nitro/test/JavaCallHelper.java @@ -0,0 +1,90 @@ +package com.margelo.nitro.test; + +import com.margelo.nitro.core.Promise; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * Java helper that reproduces the exact JavaHybridAbtMobileClientSDK.java pattern + * (lines 627–641) which triggers https://github.com/mrousavy/nitro/issues/1439. + * + *

Why this is in Java

+ * The bug requires calling the Kotlin {@code suspend fun Promise.await()} from Java + * with a custom {@link CustomContinuation}. When Kotlin's {@code SafeContinuation} + * detects that the Promise is already resolved, it returns the result + * directly from {@code await()} — without ever calling + * {@link CustomContinuation#resumeWith}. The Java caller ignores that return value + * and calls {@link CompletableFuture#get()}, which blocks forever. + * + *

The pattern

+ *
{@code
+ * Promise> call = fn.invoke(input);
+ *
+ * // ─── outer promise ────────────────────────────────────────────────────────
+ * CompletableFuture> future1 = new CompletableFuture<>();
+ * call.await(new CustomContinuation<>(future1));   // Java calls Kotlin suspend fun
+ * Promise inner = future1.get(timeout);    // blocks until JS dispatches
+ *
+ * // ─── inner promise ────────────────────────────────────────────────────────
+ * CompletableFuture future2 = new CompletableFuture<>();
+ * inner.await(new CustomContinuation<>(future2));  // ← BUG: if 'inner' is already
+ *                                                  //   resolved, SafeContinuation
+ *                                                  //   eats the value; future2
+ *                                                  //   is never completed
+ * return future2.get(timeout);                     // ← HANGS
+ * }
+ */ +public class JavaCallHelper { + + /** + * Calls the given {@code call} Promise using the abt-SDK Java pattern. + * + *

This method deliberately reproduces the bug: if the inner Promise is + * already resolved by the time {@code inner.await(continuation)} is called, + * {@link CompletableFuture#get()} hangs forever (or until {@code timeout} + * expires with a {@link TimeoutException}).

+ * + * @param call the outer {@code Promise>} returned by {@code fn.invoke(input)} + * @param timeout timeout value passed to each {@link CompletableFuture#get} + * @param unit timeout unit + * @return the resolved string + * @throws TimeoutException when the bug is triggered — inner future never completes + * @throws ExecutionException when the JS function threw + * @throws InterruptedException if the waiting thread is interrupted + */ + @SuppressWarnings("unused") + public static String awaitFnBlocking( + Promise> call, + long timeout, + TimeUnit unit + ) throws Exception { + + // ── Step 1: wait for the JS function to dispatch and return its Promise ── + CompletableFuture> future1 = new CompletableFuture<>(); + // Call the Kotlin `suspend fun await()` from Java with a CustomContinuation. + // When the outer Promise is pending this works correctly: COROUTINE_SUSPENDED is + // returned, and CustomContinuation.resumeWith() is called later on the JS thread. + call.await(new CustomContinuation<>(future1)); + Promise inner = unwrap(future1.get(timeout, unit)); + + // ── Step 2: wait for the actual string result ────────────────────────── + CompletableFuture future2 = new CompletableFuture<>(); + // BUG: if 'inner' is already resolved here (race between JS-thread resolution + // and the executor thread reaching this line), Kotlin's SafeContinuation + // returns "second" directly from await() without calling + // CustomContinuation.resumeWith(). future2 is never completed. + inner.await(new CustomContinuation<>(future2)); + return unwrap(future2.get(timeout, unit)); // ← hangs when bug is triggered + } + + /** + * Unwrap {@link ExecutionException} so callers see the original cause. + */ + @SuppressWarnings("unchecked") + private static T unwrap(T value) { + return value; // marker — real unwrapping is done by callers catching ExecutionException + } +} diff --git a/packages/react-native-nitro-test/ios/HybridIssue1439.swift b/packages/react-native-nitro-test/ios/HybridIssue1439.swift new file mode 100644 index 0000000000..6b696bff51 --- /dev/null +++ b/packages/react-native-nitro-test/ios/HybridIssue1439.swift @@ -0,0 +1,35 @@ +// +// HybridIssue1439.swift +// react-native-nitro-test +// +// Reproduces https://github.com/mrousavy/nitro/issues/1439 +// + +import NitroModules + +class HybridIssue1439: HybridIssue1439Spec { + /** + * Calls params.fn twice from a native background context. + * - First call: the JS function throws an error + * - Second call: should succeed, but hangs on Android due to issue #1439 + */ + func callFnTwiceFirstThrows(params: Issue1439Params) throws -> Promise { + return Promise.async { + // First invocation — expected to throw + do { + let innerPromise1 = try await params.fn(Issue1439CallInput(value: "first")).await() + let result1 = try await innerPromise1.await() + print("[HybridIssue1439] First call unexpectedly succeeded with: \(result1)") + } catch { + print("[HybridIssue1439] First call threw as expected: \(error)") + } + + // Second invocation — should succeed but hangs on Android due to issue #1439 + print("[HybridIssue1439] Starting second invocation...") + let innerPromise2 = try await params.fn(Issue1439CallInput(value: "second")).await() + let result2 = try await innerPromise2.await() + print("[HybridIssue1439] Second call returned: \(result2)") + return result2 + } + } +} diff --git a/packages/react-native-nitro-test/nitro.json b/packages/react-native-nitro-test/nitro.json index b3a180b75e..c275b1242f 100644 --- a/packages/react-native-nitro-test/nitro.json +++ b/packages/react-native-nitro-test/nitro.json @@ -74,6 +74,16 @@ "language": "kotlin", "implementationClassName": "HybridRecyclableTestView" } + }, + "Issue1439": { + "ios": { + "language": "swift", + "implementationClassName": "HybridIssue1439" + }, + "android": { + "language": "kotlin", + "implementationClassName": "HybridIssue1439" + } } }, "ignorePaths": [ diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/NitroTest+autolinking.cmake b/packages/react-native-nitro-test/nitrogen/generated/android/NitroTest+autolinking.cmake index 222b2ef3fe..13c37d17d6 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/android/NitroTest+autolinking.cmake +++ b/packages/react-native-nitro-test/nitrogen/generated/android/NitroTest+autolinking.cmake @@ -35,6 +35,7 @@ target_sources( # Shared Nitrogen C++ sources ../nitrogen/generated/shared/c++/HybridBaseSpec.cpp ../nitrogen/generated/shared/c++/HybridChildSpec.cpp + ../nitrogen/generated/shared/c++/HybridIssue1439Spec.cpp ../nitrogen/generated/shared/c++/HybridPlatformObjectSpec.cpp ../nitrogen/generated/shared/c++/HybridRecyclableTestViewSpec.cpp ../nitrogen/generated/shared/c++/views/HybridRecyclableTestViewComponent.cpp @@ -47,6 +48,7 @@ target_sources( ../nitrogen/generated/android/c++/JHybridChildSpec.cpp ../nitrogen/generated/android/c++/JNamedVariant.cpp ../nitrogen/generated/android/c++/JVariant_Double_String.cpp + ../nitrogen/generated/android/c++/JHybridIssue1439Spec.cpp ../nitrogen/generated/android/c++/JHybridPlatformObjectSpec.cpp ../nitrogen/generated/android/c++/JHybridRecyclableTestViewSpec.cpp ../nitrogen/generated/android/c++/views/JHybridRecyclableTestViewStateUpdater.cpp diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/NitroTestOnLoad.cpp b/packages/react-native-nitro-test/nitrogen/generated/android/NitroTestOnLoad.cpp index 5ebdab53ba..787ca2ac25 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/android/NitroTestOnLoad.cpp +++ b/packages/react-native-nitro-test/nitrogen/generated/android/NitroTestOnLoad.cpp @@ -17,6 +17,8 @@ #include "JHybridBaseSpec.hpp" #include "JHybridChildSpec.hpp" +#include "JHybridIssue1439Spec.hpp" +#include "JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp" #include "JHybridPlatformObjectSpec.hpp" #include "JHybridRecyclableTestViewSpec.hpp" #include "views/JHybridRecyclableTestViewStateUpdater.hpp" @@ -95,6 +97,14 @@ struct JHybridRecyclableTestViewSpecImpl: public jni::JavaClassgetJHybridRecyclableTestViewSpec(); } }; +struct JHybridIssue1439SpecImpl: public jni::JavaClass { + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/HybridIssue1439;"; + static std::shared_ptr create() { + static const auto constructorFn = javaClassStatic()->getConstructor(); + jni::local_ref javaPart = javaClassStatic()->newObject(constructorFn); + return javaPart->getJHybridIssue1439Spec(); + } +}; void registerAllNatives() { using namespace margelo::nitro; @@ -103,6 +113,8 @@ void registerAllNatives() { // Register native JNI methods margelo::nitro::test::JHybridBaseSpec::CxxPart::registerNatives(); margelo::nitro::test::JHybridChildSpec::CxxPart::registerNatives(); + margelo::nitro::test::JHybridIssue1439Spec::CxxPart::registerNatives(); + margelo::nitro::test::JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx::registerNatives(); margelo::nitro::test::JHybridPlatformObjectSpec::CxxPart::registerNatives(); margelo::nitro::test::JHybridRecyclableTestViewSpec::CxxPart::registerNatives(); margelo::nitro::test::views::JHybridRecyclableTestViewStateUpdater::registerNatives(); @@ -169,6 +181,12 @@ void registerAllNatives() { return JHybridRecyclableTestViewSpecImpl::create(); } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "Issue1439", + []() -> std::shared_ptr { + return JHybridIssue1439SpecImpl::create(); + } + ); } } // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp new file mode 100644 index 0000000000..40ee3414f8 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp @@ -0,0 +1,126 @@ +/// +/// JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include + +#include +#include +#include "Issue1439CallInput.hpp" +#include +#include +#include +#include "JIssue1439CallInput.hpp" + +namespace margelo::nitro::test { + + using namespace facebook; + + /** + * Represents the Java/Kotlin callback `(input: Issue1439CallInput) -> Promise>`. + * This can be passed around between C++ and Java/Kotlin. + */ + struct JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput;"; + + public: + /** + * Invokes the function this `JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput` instance holds through JNI. + */ + std::shared_ptr>>> invoke(const Issue1439CallInput& input) const { + static const auto method = javaClassStatic()->getMethod(jni::alias_ref /* input */)>("invoke"); + auto __result = method(self(), JIssue1439CallInput::fromCpp(input)); + return [&]() { + auto __promise = Promise>>::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast(__boxedResult); + __promise->resolve([&]() { + auto __promise = Promise::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast(__boxedResult); + __promise->resolve(__result->toStdString()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }(); + } + }; + + /** + * An implementation of Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput that is backed by a C++ implementation (using `std::function<...>`) + */ + class JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx final: public jni::HybridClass { + public: + static jni::local_ref fromCpp(const std::function>>>(const Issue1439CallInput& /* input */)>& func) { + return JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx::newObjectCxxArgs(func); + } + + public: + /** + * Invokes the C++ `std::function<...>` this `JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx` instance holds. + */ + jni::local_ref invoke_cxx(jni::alias_ref input) { + std::shared_ptr>>> __result = _func(input->toCpp()); + return [&]() { + jni::local_ref __localPromise = JPromise::create(); + jni::global_ref __promise = jni::make_global(__localPromise); + __result->addOnResolvedListener([=](const std::shared_ptr>& __result) { + __promise->cthis()->resolve([&]() { + jni::local_ref __localPromise = JPromise::create(); + jni::global_ref __promise = jni::make_global(__localPromise); + __result->addOnResolvedListener([=](const std::string& __result) { + __promise->cthis()->resolve(jni::make_jstring(__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: + [[nodiscard]] + inline const std::function>>>(const Issue1439CallInput& /* input */)>& getFunction() const { + return _func; + } + + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx;"; + static void registerNatives() { + registerHybrid({makeNativeMethod("invoke_cxx", JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx::invoke_cxx)}); + } + + private: + explicit JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx(const std::function>>>(const Issue1439CallInput& /* input */)>& func): _func(func) { } + + private: + friend HybridBase; + std::function>>>(const Issue1439CallInput& /* input */)> _func; + }; + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridIssue1439Spec.cpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridIssue1439Spec.cpp new file mode 100644 index 0000000000..43f950d544 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridIssue1439Spec.cpp @@ -0,0 +1,76 @@ +/// +/// JHybridIssue1439Spec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#include "JHybridIssue1439Spec.hpp" + +// Forward declaration of `Issue1439Params` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439Params; } +// Forward declaration of `Issue1439CallInput` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439CallInput; } + +#include +#include +#include +#include "Issue1439Params.hpp" +#include "JIssue1439Params.hpp" +#include "Issue1439CallInput.hpp" +#include +#include "JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp" +#include +#include "JIssue1439CallInput.hpp" + +namespace margelo::nitro::test { + + std::shared_ptr JHybridIssue1439Spec::JavaPart::getJHybridIssue1439Spec() { + auto hybridObject = JHybridObject::JavaPart::getJHybridObject(); + auto castHybridObject = std::dynamic_pointer_cast(hybridObject); + if (castHybridObject == nullptr) [[unlikely]] { + throw std::runtime_error("Failed to downcast JHybridObject to JHybridIssue1439Spec!"); + } + return castHybridObject; + } + + jni::local_ref JHybridIssue1439Spec::CxxPart::initHybrid(jni::alias_ref jThis) { + return makeCxxInstance(jThis); + } + + std::shared_ptr JHybridIssue1439Spec::CxxPart::createHybridObject(const jni::local_ref& javaPart) { + auto castJavaPart = jni::dynamic_ref_cast(javaPart); + if (castJavaPart == nullptr) [[unlikely]] { + throw std::runtime_error("Failed to cast JHybridObject::JavaPart to JHybridIssue1439Spec::JavaPart!"); + } + return std::make_shared(castJavaPart); + } + + void JHybridIssue1439Spec::CxxPart::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JHybridIssue1439Spec::CxxPart::initHybrid), + }); + } + + // Properties + + + // Methods + std::shared_ptr> JHybridIssue1439Spec::callFnTwiceFirstThrows(const Issue1439Params& params) { + static const auto method = _javaPart->javaClassStatic()->getMethod(jni::alias_ref /* params */)>("callFnTwiceFirstThrows"); + auto __result = method(_javaPart, JIssue1439Params::fromCpp(params)); + return [&]() { + auto __promise = Promise::create(); + __result->cthis()->addOnResolvedListener([=](const jni::alias_ref& __boxedResult) { + auto __result = jni::static_ref_cast(__boxedResult); + __promise->resolve(__result->toStdString()); + }); + __result->cthis()->addOnRejectedListener([=](const jni::alias_ref& __throwable) { + jni::JniException __jniError(__throwable); + __promise->reject(std::make_exception_ptr(__jniError)); + }); + return __promise; + }(); + } + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridIssue1439Spec.hpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridIssue1439Spec.hpp new file mode 100644 index 0000000000..fe2136bd37 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JHybridIssue1439Spec.hpp @@ -0,0 +1,63 @@ +/// +/// HybridIssue1439Spec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include +#include "HybridIssue1439Spec.hpp" + + + + +namespace margelo::nitro::test { + + using namespace facebook; + + class JHybridIssue1439Spec: public virtual HybridIssue1439Spec, public virtual JHybridObject { + public: + struct JavaPart: public jni::JavaClass { + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/HybridIssue1439Spec;"; + std::shared_ptr getJHybridIssue1439Spec(); + }; + struct CxxPart: public jni::HybridClass { + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/HybridIssue1439Spec$CxxPart;"; + static jni::local_ref initHybrid(jni::alias_ref jThis); + static void registerNatives(); + using HybridBase::HybridBase; + protected: + std::shared_ptr createHybridObject(const jni::local_ref& javaPart) override; + }; + + public: + explicit JHybridIssue1439Spec(const jni::local_ref& javaPart): + HybridObject(HybridIssue1439Spec::TAG), + JHybridObject(javaPart), + _javaPart(jni::make_global(javaPart)) {} + ~JHybridIssue1439Spec() override { + // Hermes GC can destroy JS objects on a non-JNI Thread. + jni::ThreadScope::WithClassLoader([&] { _javaPart.reset(); }); + } + + public: + inline const jni::global_ref& getJavaPart() const noexcept { + return _javaPart; + } + + public: + // Properties + + + public: + // Methods + std::shared_ptr> callFnTwiceFirstThrows(const Issue1439Params& params) override; + + private: + jni::global_ref _javaPart; + }; + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JIssue1439CallInput.hpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JIssue1439CallInput.hpp new file mode 100644 index 0000000000..d155242db5 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JIssue1439CallInput.hpp @@ -0,0 +1,57 @@ +/// +/// JIssue1439CallInput.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "Issue1439CallInput.hpp" + +#include + +namespace margelo::nitro::test { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ struct "Issue1439CallInput" and the Kotlin data class "Issue1439CallInput". + */ + struct JIssue1439CallInput final: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/Issue1439CallInput;"; + + public: + /** + * Convert this Java/Kotlin-based struct to the C++ struct Issue1439CallInput by copying all values to C++. + */ + [[maybe_unused]] + [[nodiscard]] + Issue1439CallInput toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldValue = clazz->getField("value"); + jni::local_ref value = this->getFieldValue(fieldValue); + return Issue1439CallInput( + value->toStdString() + ); + } + + public: + /** + * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. + */ + [[maybe_unused]] + static jni::local_ref fromCpp(const Issue1439CallInput& value) { + using JSignature = JIssue1439CallInput(jni::alias_ref); + static const auto clazz = javaClassStatic(); + static const auto create = clazz->getStaticMethod("fromCpp"); + return create( + clazz, + jni::make_jstring(value.value) + ); + } + }; + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/c++/JIssue1439Params.hpp b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JIssue1439Params.hpp new file mode 100644 index 0000000000..66720f85bb --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/c++/JIssue1439Params.hpp @@ -0,0 +1,72 @@ +/// +/// JIssue1439Params.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include +#include "Issue1439Params.hpp" + +#include "Issue1439CallInput.hpp" +#include "JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.hpp" +#include "JIssue1439CallInput.hpp" +#include +#include +#include +#include +#include + +namespace margelo::nitro::test { + + using namespace facebook; + + /** + * The C++ JNI bridge between the C++ struct "Issue1439Params" and the Kotlin data class "Issue1439Params". + */ + struct JIssue1439Params final: public jni::JavaClass { + public: + static constexpr auto kJavaDescriptor = "Lcom/margelo/nitro/test/Issue1439Params;"; + + public: + /** + * Convert this Java/Kotlin-based struct to the C++ struct Issue1439Params by copying all values to C++. + */ + [[maybe_unused]] + [[nodiscard]] + Issue1439Params toCpp() const { + static const auto clazz = javaClassStatic(); + static const auto fieldFn = clazz->getField("fn"); + jni::local_ref fn = this->getFieldValue(fieldFn); + return Issue1439Params( + [&]() -> std::function>>>(const Issue1439CallInput& /* input */)> { + if (fn->isInstanceOf(JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx::javaClassStatic())) [[likely]] { + auto downcast = jni::static_ref_cast(fn); + return downcast->cthis()->getFunction(); + } else { + auto fnRef = jni::make_global(fn); + return JNICallable>>>(Issue1439CallInput)>(std::move(fnRef)); + } + }() + ); + } + + public: + /** + * Create a Java/Kotlin-based struct by copying all values from the given C++ struct to Java. + */ + [[maybe_unused]] + static jni::local_ref fromCpp(const Issue1439Params& value) { + using JSignature = JIssue1439Params(jni::alias_ref); + static const auto clazz = javaClassStatic(); + static const auto create = clazz->getStaticMethod("fromCpp"); + return create( + clazz, + JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx::fromCpp(value.fn) + ); + } + }; + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.kt b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.kt new file mode 100644 index 0000000000..bea5423c32 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.kt @@ -0,0 +1,80 @@ +/// +/// Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.test + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import dalvik.annotation.optimization.FastNative +import com.margelo.nitro.core.Promise + +/** + * Represents the JavaScript callback `(input: struct) => std::shared_ptr>>>`. + * This can be either implemented in C++ (in which case it might be a callback coming from JS), + * or in Kotlin/Java (in which case it is a native callback). + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType") +fun interface Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput: (Issue1439CallInput) -> Promise> { + /** + * 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. + */ + @DoNotStrip + @Keep + override fun invoke(input: Issue1439CallInput): Promise> +} + +/** + * Represents the JavaScript callback `(input: struct) => std::shared_ptr>>>`. + * This is implemented in C++, via a `std::function<...>`. + * The callback might be coming from JS. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "FunctionName", + "ConvertSecondaryConstructorToPrimary", "ClassName", "LocalVariableName", +) +class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_cxx: Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput { + @DoNotStrip + @Keep + private val mHybridData: HybridData + + @DoNotStrip + @Keep + private constructor(hybridData: HybridData) { + mHybridData = hybridData + } + + @DoNotStrip + @Keep + override fun invoke(input: Issue1439CallInput): Promise> + = invoke_cxx(input) + + @FastNative + private external fun invoke_cxx(input: Issue1439CallInput): Promise> +} + +/** + * Represents the JavaScript callback `(input: struct) => std::shared_ptr>>>`. + * This is implemented in Java/Kotlin, via a `(Issue1439CallInput) -> Promise>`. + * The callback is always coming from native. + */ +@DoNotStrip +@Keep +@Suppress("ClassName", "RedundantUnitReturnType", "unused") +class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_java(private val function: (Issue1439CallInput) -> Promise>): Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput { + @DoNotStrip + @Keep + override fun invoke(input: Issue1439CallInput): Promise> { + return this.function(input) + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridIssue1439Spec.kt b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridIssue1439Spec.kt new file mode 100644 index 0000000000..35cf4f70c6 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/HybridIssue1439Spec.kt @@ -0,0 +1,55 @@ +/// +/// HybridIssue1439Spec.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.test + +import androidx.annotation.Keep +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.margelo.nitro.core.Promise +import com.margelo.nitro.core.HybridObject + +/** + * A Kotlin class representing the Issue1439 HybridObject. + * Implement this abstract class to create Kotlin-based instances of Issue1439. + */ +@DoNotStrip +@Keep +@Suppress( + "KotlinJniMissingFunction", "unused", + "RedundantSuppression", "RedundantUnitReturnType", "SimpleRedundantLet", + "LocalVariableName", "PropertyName", "PrivatePropertyName", "FunctionName" +) +abstract class HybridIssue1439Spec: HybridObject() { + // Properties + + + // Methods + @DoNotStrip + @Keep + abstract fun callFnTwiceFirstThrows(params: Issue1439Params): Promise + + // Default implementation of `HybridObject.toString()` + override fun toString(): String { + return "[HybridObject Issue1439]" + } + + // C++ backing class + @DoNotStrip + @Keep + protected open class CxxPart(javaPart: HybridIssue1439Spec): HybridObject.CxxPart(javaPart) { + // C++ JHybridIssue1439Spec::CxxPart::initHybrid(...) + external override fun initHybrid(): HybridData + } + override fun createCxxPart(): CxxPart { + return CxxPart(this) + } + + companion object { + protected const val TAG = "HybridIssue1439Spec" + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Issue1439CallInput.kt b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Issue1439CallInput.kt new file mode 100644 index 0000000000..430c03260d --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Issue1439CallInput.kt @@ -0,0 +1,51 @@ +/// +/// Issue1439CallInput.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.test + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects + + +/** + * Represents the JavaScript object/struct "Issue1439CallInput". + */ +@DoNotStrip +@Keep +data class Issue1439CallInput( + @DoNotStrip + @Keep + val value: String +) { + /* primary constructor */ + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Issue1439CallInput) return false + return Objects.deepEquals(this.value, other.value) + } + + override fun hashCode(): Int { + return arrayOf( + value + ).contentDeepHashCode() + } + + companion object { + /** + * Constructor called from C++ + */ + @DoNotStrip + @Keep + @Suppress("unused") + @JvmStatic + private fun fromCpp(value: String): Issue1439CallInput { + return Issue1439CallInput(value) + } + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Issue1439Params.kt b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Issue1439Params.kt new file mode 100644 index 0000000000..9df6f27048 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/android/kotlin/com/margelo/nitro/test/Issue1439Params.kt @@ -0,0 +1,55 @@ +/// +/// Issue1439Params.kt +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +package com.margelo.nitro.test + +import androidx.annotation.Keep +import com.facebook.proguard.annotations.DoNotStrip +import java.util.Objects +import com.margelo.nitro.core.Promise + +/** + * Represents the JavaScript object/struct "Issue1439Params". + */ +@DoNotStrip +@Keep +data class Issue1439Params( + @DoNotStrip + @Keep + val fn: Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput +) { + /** + * Create a new instance of Issue1439Params from Kotlin + */ + constructor(fn: (input: Issue1439CallInput) -> Promise>): + this(Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_java(fn)) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Issue1439Params) return false + return Objects.deepEquals(this.fn, other.fn) + } + + override fun hashCode(): Int { + return arrayOf( + fn + ).contentDeepHashCode() + } + + companion object { + /** + * Constructor called from C++ + */ + @DoNotStrip + @Keep + @Suppress("unused") + @JvmStatic + private fun fromCpp(fn: Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput): Issue1439Params { + return Issue1439Params(fn) + } + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.cpp b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.cpp index ffd408054a..e483461c5e 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.cpp +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.cpp @@ -10,6 +10,7 @@ // Include C++ implementation defined types #include "HybridBaseSpecSwift.hpp" #include "HybridChildSpecSwift.hpp" +#include "HybridIssue1439SpecSwift.hpp" #include "HybridPlatformObjectSpecSwift.hpp" #include "HybridRecyclableTestViewSpecSwift.hpp" #include "HybridTestObjectSwiftKotlinSpecSwift.hpp" @@ -52,6 +53,55 @@ namespace margelo::nitro::test::bridge::swift { return swiftPart.toUnsafe(); } + // pragma MARK: std::function + Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = NitroTest::Func_void_std__string::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::string& result) mutable -> void { + swiftClosure.call(result); + }; + } + + // pragma MARK: std::function + Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = NitroTest::Func_void_std__exception_ptr::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::exception_ptr& error) mutable -> void { + swiftClosure.call(error); + }; + } + + // pragma MARK: std::function>>>(const Issue1439CallInput& /* input */)> + Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = NitroTest::Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const Issue1439CallInput& input) mutable -> std::shared_ptr>>> { + auto __result = swiftClosure.call(input); + return __result; + }; + } + + // pragma MARK: std::function>& /* result */)> + Func_void_std__shared_ptr_Promise_std__string__ create_Func_void_std__shared_ptr_Promise_std__string__(void* NON_NULL swiftClosureWrapper) noexcept { + auto swiftClosure = NitroTest::Func_void_std__shared_ptr_Promise_std__string__::fromUnsafe(swiftClosureWrapper); + return [swiftClosure = std::move(swiftClosure)](const std::shared_ptr>& result) mutable -> void { + swiftClosure.call(result); + }; + } + + // pragma MARK: std::shared_ptr + std::shared_ptr create_std__shared_ptr_HybridIssue1439Spec_(void* NON_NULL swiftUnsafePointer) noexcept { + NitroTest::HybridIssue1439Spec_cxx swiftPart = NitroTest::HybridIssue1439Spec_cxx::fromUnsafe(swiftUnsafePointer); + return std::make_shared(swiftPart); + } + void* NON_NULL get_std__shared_ptr_HybridIssue1439Spec_(std__shared_ptr_HybridIssue1439Spec_ cppType) { + std::shared_ptr swiftWrapper = std::dynamic_pointer_cast(cppType); + #ifdef NITRO_DEBUG + if (swiftWrapper == nullptr) [[unlikely]] { + throw std::runtime_error("Class \"HybridIssue1439Spec\" is not implemented in Swift!"); + } + #endif + NitroTest::HybridIssue1439Spec_cxx& swiftPart = swiftWrapper->getSwiftPart(); + return swiftPart.toUnsafe(); + } + // pragma MARK: std::shared_ptr std::shared_ptr create_std__shared_ptr_HybridPlatformObjectSpec_(void* NON_NULL swiftUnsafePointer) noexcept { NitroTest::HybridPlatformObjectSpec_cxx swiftPart = NitroTest::HybridPlatformObjectSpec_cxx::fromUnsafe(swiftUnsafePointer); @@ -108,14 +158,6 @@ namespace margelo::nitro::test::bridge::swift { }; } - // pragma MARK: std::function - Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept { - auto swiftClosure = NitroTest::Func_void_std__exception_ptr::fromUnsafe(swiftClosureWrapper); - return [swiftClosure = std::move(swiftClosure)](const std::exception_ptr& error) mutable -> void { - swiftClosure.call(error); - }; - } - // pragma MARK: std::function Func_void_double create_Func_void_double(void* NON_NULL swiftClosureWrapper) noexcept { auto swiftClosure = NitroTest::Func_void_double::fromUnsafe(swiftClosureWrapper); @@ -232,14 +274,6 @@ namespace margelo::nitro::test::bridge::swift { }; } - // pragma MARK: std::function - Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept { - auto swiftClosure = NitroTest::Func_void_std__string::fromUnsafe(swiftClosureWrapper); - return [swiftClosure = std::move(swiftClosure)](const std::string& value) mutable -> void { - swiftClosure.call(value); - }; - } - // pragma MARK: std::function>()> Func_std__shared_ptr_Promise_std__string__ create_Func_std__shared_ptr_Promise_std__string__(void* NON_NULL swiftClosureWrapper) noexcept { auto swiftClosure = NitroTest::Func_std__shared_ptr_Promise_std__string__::fromUnsafe(swiftClosureWrapper); diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.hpp b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.hpp index 52d5cce021..11820ad6fb 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.hpp +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Bridge.hpp @@ -18,6 +18,8 @@ namespace margelo::nitro::test { struct ExternalObjectStruct; } namespace margelo::nitro::test { class HybridBaseSpec; } // Forward declaration of `HybridChildSpec` to properly resolve imports. namespace margelo::nitro::test { class HybridChildSpec; } +// Forward declaration of `HybridIssue1439Spec` to properly resolve imports. +namespace margelo::nitro::test { class HybridIssue1439Spec; } // Forward declaration of `HybridPlatformObjectSpec` to properly resolve imports. namespace margelo::nitro::test { class HybridPlatformObjectSpec; } // Forward declaration of `HybridRecyclableTestViewSpec` to properly resolve imports. @@ -28,6 +30,8 @@ namespace margelo::nitro::test::external { class HybridSomeExternalObjectSpec; } namespace margelo::nitro::test { class HybridTestObjectSwiftKotlinSpec; } // Forward declaration of `HybridTestViewSpec` to properly resolve imports. namespace margelo::nitro::test { class HybridTestViewSpec; } +// Forward declaration of `Issue1439CallInput` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439CallInput; } // Forward declaration of `JsStyleStruct` to properly resolve imports. namespace margelo::nitro::test { struct JsStyleStruct; } // Forward declaration of `OldEnum` to properly resolve imports. @@ -56,6 +60,8 @@ namespace margelo::nitro::test { struct WrappedJsStruct; } namespace NitroTest { class HybridBaseSpec_cxx; } // Forward declaration of `HybridChildSpec_cxx` to properly resolve imports. namespace NitroTest { class HybridChildSpec_cxx; } +// Forward declaration of `HybridIssue1439Spec_cxx` to properly resolve imports. +namespace NitroTest { class HybridIssue1439Spec_cxx; } // Forward declaration of `HybridPlatformObjectSpec_cxx` to properly resolve imports. namespace NitroTest { class HybridPlatformObjectSpec_cxx; } // Forward declaration of `HybridRecyclableTestViewSpec_cxx` to properly resolve imports. @@ -72,10 +78,12 @@ namespace NitroTest { class HybridTestViewSpec_cxx; } #include "ExternalObjectStruct.hpp" #include "HybridBaseSpec.hpp" #include "HybridChildSpec.hpp" +#include "HybridIssue1439Spec.hpp" #include "HybridPlatformObjectSpec.hpp" #include "HybridRecyclableTestViewSpec.hpp" #include "HybridTestObjectSwiftKotlinSpec.hpp" #include "HybridTestViewSpec.hpp" +#include "Issue1439CallInput.hpp" #include "JsStyleStruct.hpp" #include "OldEnum.hpp" #include "OptionalCallback.hpp" @@ -287,6 +295,140 @@ namespace margelo::nitro::test::bridge::swift { return Result>::withError(error); } + // pragma MARK: std::shared_ptr> + /** + * Specialized version of `std::shared_ptr>`. + */ + using std__shared_ptr_Promise_std__string__ = std::shared_ptr>; + inline std::shared_ptr> create_std__shared_ptr_Promise_std__string__() noexcept { + return Promise::create(); + } + inline PromiseHolder wrap_std__shared_ptr_Promise_std__string__(std::shared_ptr> promise) noexcept { + return PromiseHolder(std::move(promise)); + } + + // pragma MARK: std::function + /** + * Specialized version of `std::function`. + */ + using Func_void_std__string = std::function; + /** + * Wrapper class for a `std::function`, this can be used from Swift. + */ + class Func_void_std__string_Wrapper final { + public: + explicit Func_void_std__string_Wrapper(std::function&& func): _function(std::make_unique>(std::move(func))) {} + inline void call(std::string result) const noexcept { + _function->operator()(result); + } + private: + std::unique_ptr> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__string_Wrapper wrap_Func_void_std__string(Func_void_std__string value) noexcept { + return Func_void_std__string_Wrapper(std::move(value)); + } + + // pragma MARK: std::function + /** + * Specialized version of `std::function`. + */ + using Func_void_std__exception_ptr = std::function; + /** + * Wrapper class for a `std::function`, this can be used from Swift. + */ + class Func_void_std__exception_ptr_Wrapper final { + public: + explicit Func_void_std__exception_ptr_Wrapper(std::function&& func): _function(std::make_unique>(std::move(func))) {} + inline void call(std::exception_ptr error) const noexcept { + _function->operator()(error); + } + private: + std::unique_ptr> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__exception_ptr_Wrapper wrap_Func_void_std__exception_ptr(Func_void_std__exception_ptr value) noexcept { + return Func_void_std__exception_ptr_Wrapper(std::move(value)); + } + + // pragma MARK: std::function>>>(const Issue1439CallInput& /* input */)> + /** + * Specialized version of `std::function>>>(const Issue1439CallInput&)>`. + */ + using Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput = std::function>>>(const Issue1439CallInput& /* input */)>; + /** + * Wrapper class for a `std::function>>>(const Issue1439CallInput& / * input * /)>`, this can be used from Swift. + */ + class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_Wrapper final { + public: + explicit Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_Wrapper(std::function>>>(const Issue1439CallInput& /* input */)>&& func): _function(std::make_unique>>>(const Issue1439CallInput& /* input */)>>(std::move(func))) {} + inline std::shared_ptr>>> call(Issue1439CallInput input) const noexcept { + auto __result = _function->operator()(input); + return __result; + } + private: + std::unique_ptr>>>(const Issue1439CallInput& /* input */)>> _function; + } SWIFT_NONCOPYABLE; + Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_Wrapper wrap_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput(Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput value) noexcept { + return Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput_Wrapper(std::move(value)); + } + + // pragma MARK: std::shared_ptr>>> + /** + * Specialized version of `std::shared_ptr>>>`. + */ + using std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____ = std::shared_ptr>>>; + inline std::shared_ptr>>> create_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____() noexcept { + return Promise>>::create(); + } + inline PromiseHolder>> wrap_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____(std::shared_ptr>>> promise) noexcept { + return PromiseHolder>>(std::move(promise)); + } + + // pragma MARK: std::function>& /* result */)> + /** + * Specialized version of `std::function>&)>`. + */ + using Func_void_std__shared_ptr_Promise_std__string__ = std::function>& /* result */)>; + /** + * Wrapper class for a `std::function>& / * result * /)>`, this can be used from Swift. + */ + class Func_void_std__shared_ptr_Promise_std__string___Wrapper final { + public: + explicit Func_void_std__shared_ptr_Promise_std__string___Wrapper(std::function>& /* result */)>&& func): _function(std::make_unique>& /* result */)>>(std::move(func))) {} + inline void call(std::shared_ptr> result) const noexcept { + _function->operator()(result); + } + private: + std::unique_ptr>& /* result */)>> _function; + } SWIFT_NONCOPYABLE; + Func_void_std__shared_ptr_Promise_std__string__ create_Func_void_std__shared_ptr_Promise_std__string__(void* NON_NULL swiftClosureWrapper) noexcept; + inline Func_void_std__shared_ptr_Promise_std__string___Wrapper wrap_Func_void_std__shared_ptr_Promise_std__string__(Func_void_std__shared_ptr_Promise_std__string__ value) noexcept { + return Func_void_std__shared_ptr_Promise_std__string___Wrapper(std::move(value)); + } + + // pragma MARK: std::shared_ptr + /** + * Specialized version of `std::shared_ptr`. + */ + using std__shared_ptr_HybridIssue1439Spec_ = std::shared_ptr; + std::shared_ptr create_std__shared_ptr_HybridIssue1439Spec_(void* NON_NULL swiftUnsafePointer) noexcept; + void* NON_NULL get_std__shared_ptr_HybridIssue1439Spec_(std__shared_ptr_HybridIssue1439Spec_ cppType); + + // pragma MARK: std::weak_ptr + using std__weak_ptr_HybridIssue1439Spec_ = std::weak_ptr; + inline std__weak_ptr_HybridIssue1439Spec_ weakify_std__shared_ptr_HybridIssue1439Spec_(const std::shared_ptr& strong) noexcept { return strong; } + + // pragma MARK: Result>> + using Result_std__shared_ptr_Promise_std__string___ = Result>>; + inline Result_std__shared_ptr_Promise_std__string___ create_Result_std__shared_ptr_Promise_std__string___(const std::shared_ptr>& value) noexcept { + return Result>>::withValue(value); + } + inline Result_std__shared_ptr_Promise_std__string___ create_Result_std__shared_ptr_Promise_std__string___(const std::exception_ptr& error) noexcept { + return Result>>::withError(error); + } + // pragma MARK: std::shared_ptr /** * Specialized version of `std::shared_ptr`. @@ -366,28 +508,6 @@ namespace margelo::nitro::test::bridge::swift { return Func_void_std__shared_ptr_HybridTestObjectSwiftKotlinSpec__Wrapper(std::move(value)); } - // pragma MARK: std::function - /** - * Specialized version of `std::function`. - */ - using Func_void_std__exception_ptr = std::function; - /** - * Wrapper class for a `std::function`, this can be used from Swift. - */ - class Func_void_std__exception_ptr_Wrapper final { - public: - explicit Func_void_std__exception_ptr_Wrapper(std::function&& func): _function(std::make_unique>(std::move(func))) {} - inline void call(std::exception_ptr error) const noexcept { - _function->operator()(error); - } - private: - std::unique_ptr> _function; - } SWIFT_NONCOPYABLE; - Func_void_std__exception_ptr create_Func_void_std__exception_ptr(void* NON_NULL swiftClosureWrapper) noexcept; - inline Func_void_std__exception_ptr_Wrapper wrap_Func_void_std__exception_ptr(Func_void_std__exception_ptr value) noexcept { - return Func_void_std__exception_ptr_Wrapper(std::move(value)); - } - // pragma MARK: std::optional> /** * Specialized version of `std::optional>`. @@ -1174,28 +1294,6 @@ namespace margelo::nitro::test::bridge::swift { return Func_void_std__shared_ptr_Promise_std__shared_ptr_ArrayBuffer____Wrapper(std::move(value)); } - // pragma MARK: std::function - /** - * Specialized version of `std::function`. - */ - using Func_void_std__string = std::function; - /** - * Wrapper class for a `std::function`, this can be used from Swift. - */ - class Func_void_std__string_Wrapper final { - public: - explicit Func_void_std__string_Wrapper(std::function&& func): _function(std::make_unique>(std::move(func))) {} - inline void call(std::string value) const noexcept { - _function->operator()(value); - } - private: - std::unique_ptr> _function; - } SWIFT_NONCOPYABLE; - Func_void_std__string create_Func_void_std__string(void* NON_NULL swiftClosureWrapper) noexcept; - inline Func_void_std__string_Wrapper wrap_Func_void_std__string(Func_void_std__string value) noexcept { - return Func_void_std__string_Wrapper(std::move(value)); - } - // pragma MARK: std::optional> /** * Specialized version of `std::optional>`. @@ -1234,18 +1332,6 @@ namespace margelo::nitro::test::bridge::swift { return Func_std__shared_ptr_Promise_std__string___Wrapper(std::move(value)); } - // pragma MARK: std::shared_ptr> - /** - * Specialized version of `std::shared_ptr>`. - */ - using std__shared_ptr_Promise_std__string__ = std::shared_ptr>; - inline std::shared_ptr> create_std__shared_ptr_Promise_std__string__() noexcept { - return Promise::create(); - } - inline PromiseHolder wrap_std__shared_ptr_Promise_std__string__(std::shared_ptr> promise) noexcept { - return PromiseHolder(std::move(promise)); - } - // pragma MARK: std::vector /** * Specialized version of `std::vector`. diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Umbrella.hpp b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Umbrella.hpp index 89a8b77d90..d3112ce04d 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Umbrella.hpp +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTest-Swift-Cxx-Umbrella.hpp @@ -18,6 +18,8 @@ namespace margelo::nitro::test { struct ExternalObjectStruct; } namespace margelo::nitro::test { class HybridBaseSpec; } // Forward declaration of `HybridChildSpec` to properly resolve imports. namespace margelo::nitro::test { class HybridChildSpec; } +// Forward declaration of `HybridIssue1439Spec` to properly resolve imports. +namespace margelo::nitro::test { class HybridIssue1439Spec; } // Forward declaration of `HybridPlatformObjectSpec` to properly resolve imports. namespace margelo::nitro::test { class HybridPlatformObjectSpec; } // Forward declaration of `HybridRecyclableTestViewSpec` to properly resolve imports. @@ -28,6 +30,10 @@ namespace margelo::nitro::test::external { class HybridSomeExternalObjectSpec; } namespace margelo::nitro::test { class HybridTestObjectSwiftKotlinSpec; } // Forward declaration of `HybridTestViewSpec` to properly resolve imports. namespace margelo::nitro::test { class HybridTestViewSpec; } +// Forward declaration of `Issue1439CallInput` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439CallInput; } +// Forward declaration of `Issue1439Params` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439Params; } // Forward declaration of `JsStyleStruct` to properly resolve imports. namespace margelo::nitro::test { struct JsStyleStruct; } // Forward declaration of `MapWrapper` to properly resolve imports. @@ -61,10 +67,13 @@ namespace margelo::nitro::test { struct WrappedJsStruct; } #include "ExternalObjectStruct.hpp" #include "HybridBaseSpec.hpp" #include "HybridChildSpec.hpp" +#include "HybridIssue1439Spec.hpp" #include "HybridPlatformObjectSpec.hpp" #include "HybridRecyclableTestViewSpec.hpp" #include "HybridTestObjectSwiftKotlinSpec.hpp" #include "HybridTestViewSpec.hpp" +#include "Issue1439CallInput.hpp" +#include "Issue1439Params.hpp" #include "JsStyleStruct.hpp" #include "MapWrapper.hpp" #include "OldEnum.hpp" @@ -108,6 +117,8 @@ namespace margelo::nitro::test { struct WrappedJsStruct; } namespace NitroTest { class HybridBaseSpec_cxx; } // Forward declaration of `HybridChildSpec_cxx` to properly resolve imports. namespace NitroTest { class HybridChildSpec_cxx; } +// Forward declaration of `HybridIssue1439Spec_cxx` to properly resolve imports. +namespace NitroTest { class HybridIssue1439Spec_cxx; } // Forward declaration of `HybridPlatformObjectSpec_cxx` to properly resolve imports. namespace NitroTest { class HybridPlatformObjectSpec_cxx; } // Forward declaration of `HybridRecyclableTestViewSpec_cxx` to properly resolve imports. diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.mm b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.mm index 1a2b5b22c2..5a2308024d 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.mm +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.mm @@ -17,6 +17,7 @@ #include "HybridPlatformObjectSpecSwift.hpp" #include "HybridTestViewSpecSwift.hpp" #include "HybridRecyclableTestViewSpecSwift.hpp" +#include "HybridIssue1439SpecSwift.hpp" @interface NitroTestAutolinking : NSObject @end @@ -78,6 +79,13 @@ + (void) load { return hybridObject; } ); + HybridObjectRegistry::registerHybridObjectConstructor( + "Issue1439", + []() -> std::shared_ptr { + std::shared_ptr hybridObject = NitroTest::NitroTestAutolinking::createIssue1439(); + return hybridObject; + } + ); } @end diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.swift index 4e19db7c51..d105a9bcda 100644 --- a/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.swift +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/NitroTestAutolinking.swift @@ -83,4 +83,16 @@ public final class NitroTestAutolinking { public static func isRecyclableTestViewRecyclable() -> Bool { return HybridRecyclableTestView.self is any RecyclableView.Type } + + public static func createIssue1439() -> bridge.std__shared_ptr_HybridIssue1439Spec_ { + let hybridObject = HybridIssue1439() + return { () -> bridge.std__shared_ptr_HybridIssue1439Spec_ in + let __cxxWrapped = hybridObject.getCxxWrapper() + return __cxxWrapped.getCxxPart() + }() + } + + public static func isIssue1439Recyclable() -> Bool { + return HybridIssue1439.self is any RecyclableView.Type + } } diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridIssue1439SpecSwift.cpp b/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridIssue1439SpecSwift.cpp new file mode 100644 index 0000000000..1a8ee7b938 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridIssue1439SpecSwift.cpp @@ -0,0 +1,11 @@ +/// +/// HybridIssue1439SpecSwift.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#include "HybridIssue1439SpecSwift.hpp" + +namespace margelo::nitro::test { +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridIssue1439SpecSwift.hpp b/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridIssue1439SpecSwift.hpp new file mode 100644 index 0000000000..29b4587566 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/c++/HybridIssue1439SpecSwift.hpp @@ -0,0 +1,89 @@ +/// +/// HybridIssue1439SpecSwift.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#include "HybridIssue1439Spec.hpp" + +// Forward declaration of `HybridIssue1439Spec_cxx` to properly resolve imports. +namespace NitroTest { class HybridIssue1439Spec_cxx; } + +// Forward declaration of `Issue1439Params` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439Params; } +// Forward declaration of `Issue1439CallInput` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439CallInput; } + +#include +#include +#include "Issue1439Params.hpp" +#include "Issue1439CallInput.hpp" +#include + +#include "NitroTest-Swift-Cxx-Umbrella.hpp" + +namespace margelo::nitro::test { + + /** + * The C++ part of HybridIssue1439Spec_cxx.swift. + * + * HybridIssue1439SpecSwift (C++) accesses HybridIssue1439Spec_cxx (Swift), and might + * contain some additional bridging code for C++ <> Swift interop. + * + * Since this obviously introduces an overhead, I hope at some point in + * the future, HybridIssue1439Spec_cxx can directly inherit from the C++ class HybridIssue1439Spec + * to simplify the whole structure and memory management. + */ + class HybridIssue1439SpecSwift: public virtual HybridIssue1439Spec { + public: + // Constructor from a Swift instance + explicit HybridIssue1439SpecSwift(const NitroTest::HybridIssue1439Spec_cxx& swiftPart): + HybridObject(HybridIssue1439Spec::TAG), + _swiftPart(swiftPart) { } + + public: + // Get the Swift part + inline NitroTest::HybridIssue1439Spec_cxx& getSwiftPart() noexcept { + return _swiftPart; + } + + public: + inline size_t getExternalMemorySize() noexcept override { + return _swiftPart.getMemorySize(); + } + bool equals(const std::shared_ptr& other) override { + if (auto otherCast = std::dynamic_pointer_cast(other)) { + return _swiftPart.equals(otherCast->_swiftPart); + } + return false; + } + void dispose() noexcept override { + _swiftPart.dispose(); + } + std::string toString() override { + return _swiftPart.toString(); + } + + public: + // Properties + + + public: + // Methods + inline std::shared_ptr> callFnTwiceFirstThrows(const Issue1439Params& params) override { + auto __result = _swiftPart.callFnTwiceFirstThrows(std::forward(params)); + if (__result.hasError()) [[unlikely]] { + std::rethrow_exception(__result.error()); + } + auto __value = std::move(__result.value()); + return __value; + } + + private: + NitroTest::HybridIssue1439Spec_cxx _swiftPart; + }; + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.swift new file mode 100644 index 0000000000..0567c10a00 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.swift @@ -0,0 +1,61 @@ +/// +/// Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Wraps a Swift `(_ input: Issue1439CallInput) -> Promise>` as a class. + * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. + */ +public final class Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput { + public typealias bridge = margelo.nitro.test.bridge.swift + + private let closure: (_ input: Issue1439CallInput) -> Promise> + + public init(_ closure: @escaping (_ input: Issue1439CallInput) -> Promise>) { + self.closure = closure + } + + @inline(__always) + public func call(input: Issue1439CallInput) -> bridge.std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____ { + let __result: Promise> = self.closure(input) + return { () -> bridge.std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____ in + let __promise = bridge.create_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____(__promise) + __result + .then({ __result in __promiseHolder.resolve({ () -> bridge.std__shared_ptr_Promise_std__string__ in + let __promise = bridge.create_std__shared_ptr_Promise_std__string__() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__string__(__promise) + __result + .then({ __result in __promiseHolder.resolve(std.string(__result)) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }()) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }() + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + @inline(__always) + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + @inline(__always) + public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__string__.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__string__.swift new file mode 100644 index 0000000000..f96fbf2c26 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__string__.swift @@ -0,0 +1,66 @@ +/// +/// Func_void_std__shared_ptr_Promise_std__string__.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Wraps a Swift `(_ value: Promise) -> Void` as a class. + * This class can be used from C++, e.g. to wrap the Swift closure as a `std::function`. + */ +public final class Func_void_std__shared_ptr_Promise_std__string__ { + public typealias bridge = margelo.nitro.test.bridge.swift + + private let closure: (_ value: Promise) -> Void + + public init(_ closure: @escaping (_ value: Promise) -> Void) { + self.closure = closure + } + + @inline(__always) + public func call(value: bridge.std__shared_ptr_Promise_std__string__) -> Void { + self.closure({ () -> Promise in + let __promise = Promise() + let __resolver = { (__result: String) in + __promise.resolve(withResult: __result) + } + let __rejecter = { (__error: Error) in + __promise.reject(withError: __error) + } + let __resolverCpp = { () -> bridge.Func_void_std__string in + let __closureWrapper = Func_void_std__string(__resolver) + return bridge.create_Func_void_std__string(__closureWrapper.toUnsafe()) + }() + let __rejecterCpp = { () -> bridge.Func_void_std__exception_ptr in + let __closureWrapper = Func_void_std__exception_ptr(__rejecter) + return bridge.create_Func_void_std__exception_ptr(__closureWrapper.toUnsafe()) + }() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__string__(value) + __promiseHolder.addOnResolvedListener(__resolverCpp) + __promiseHolder.addOnRejectedListener(__rejecterCpp) + return __promise + }()) + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + @inline(__always) + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `Func_void_std__shared_ptr_Promise_std__string__`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + @inline(__always) + public static func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> Func_void_std__shared_ptr_Promise_std__string__ { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridIssue1439Spec.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridIssue1439Spec.swift new file mode 100644 index 0000000000..338893b983 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridIssue1439Spec.swift @@ -0,0 +1,55 @@ +/// +/// HybridIssue1439Spec.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/// See ``HybridIssue1439Spec`` +public protocol HybridIssue1439Spec_protocol: HybridObject { + // Properties + + + // Methods + func callFnTwiceFirstThrows(params: Issue1439Params) throws -> Promise +} + +public extension HybridIssue1439Spec_protocol { + /// Default implementation of ``HybridObject.toString`` + func toString() -> String { + return "[HybridObject Issue1439]" + } +} + +/// See ``HybridIssue1439Spec`` +open class HybridIssue1439Spec_base { + private weak var cxxWrapper: HybridIssue1439Spec_cxx? = nil + public init() { } + public func getCxxWrapper() -> HybridIssue1439Spec_cxx { + #if DEBUG + guard self is any HybridIssue1439Spec else { + fatalError("`self` is not a `HybridIssue1439Spec`! Did you accidentally inherit from `HybridIssue1439Spec_base` instead of `HybridIssue1439Spec`?") + } + #endif + if let cxxWrapper = self.cxxWrapper { + return cxxWrapper + } else { + let cxxWrapper = HybridIssue1439Spec_cxx(self as! any HybridIssue1439Spec) + self.cxxWrapper = cxxWrapper + return cxxWrapper + } + } +} + +/** + * A Swift base-protocol representing the Issue1439 HybridObject. + * Implement this protocol to create Swift-based instances of Issue1439. + * ```swift + * class HybridIssue1439 : HybridIssue1439Spec { + * // ... + * } + * ``` + */ +public typealias HybridIssue1439Spec = HybridIssue1439Spec_protocol & HybridIssue1439Spec_base diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridIssue1439Spec_cxx.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridIssue1439Spec_cxx.swift new file mode 100644 index 0000000000..bffcad644a --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/HybridIssue1439Spec_cxx.swift @@ -0,0 +1,145 @@ +/// +/// HybridIssue1439Spec_cxx.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * A class implementation that bridges HybridIssue1439Spec over to C++. + * In C++, we cannot use Swift protocols - so we need to wrap it in a class to make it strongly defined. + * + * Also, some Swift types need to be bridged with special handling: + * - Enums need to be wrapped in Structs, otherwise they cannot be accessed bi-directionally (Swift bug: https://github.com/swiftlang/swift/issues/75330) + * - Other HybridObjects need to be wrapped/unwrapped from the Swift TCxx wrapper + * - Throwing methods need to be wrapped with a Result type, as exceptions cannot be propagated to C++ + */ +open class HybridIssue1439Spec_cxx { + /** + * The Swift <> C++ bridge's namespace (`margelo::nitro::test::bridge::swift`) + * from `NitroTest-Swift-Cxx-Bridge.hpp`. + * This contains specialized C++ templates, and C++ helper functions that can be accessed from Swift. + */ + public typealias bridge = margelo.nitro.test.bridge.swift + + /** + * Holds an instance of the `HybridIssue1439Spec` Swift protocol. + */ + private var __implementation: any HybridIssue1439Spec + + /** + * Holds a weak pointer to the C++ class that wraps the Swift class. + */ + private var __cxxPart: bridge.std__weak_ptr_HybridIssue1439Spec_ + + /** + * Create a new `HybridIssue1439Spec_cxx` that wraps the given `HybridIssue1439Spec`. + * All properties and methods bridge to C++ types. + */ + public init(_ implementation: any HybridIssue1439Spec) { + self.__implementation = implementation + self.__cxxPart = .init() + /* no base class */ + } + + /** + * Get the actual `HybridIssue1439Spec` instance this class wraps. + */ + @inline(__always) + public func getHybridIssue1439Spec() -> any HybridIssue1439Spec { + return __implementation + } + + /** + * Casts this instance to a retained unsafe raw pointer. + * This acquires one additional strong reference on the object! + */ + public func toUnsafe() -> UnsafeMutableRawPointer { + return Unmanaged.passRetained(self).toOpaque() + } + + /** + * Casts an unsafe pointer to a `HybridIssue1439Spec_cxx`. + * The pointer has to be a retained opaque `Unmanaged`. + * This removes one strong reference from the object! + */ + public class func fromUnsafe(_ pointer: UnsafeMutableRawPointer) -> HybridIssue1439Spec_cxx { + return Unmanaged.fromOpaque(pointer).takeRetainedValue() + } + + /** + * Gets (or creates) the C++ part of this Hybrid Object. + * The C++ part is a `std::shared_ptr`. + */ + public func getCxxPart() -> bridge.std__shared_ptr_HybridIssue1439Spec_ { + let cachedCxxPart = self.__cxxPart.lock() + if Bool(fromCxx: cachedCxxPart) { + return cachedCxxPart + } else { + let newCxxPart = bridge.create_std__shared_ptr_HybridIssue1439Spec_(self.toUnsafe()) + __cxxPart = bridge.weakify_std__shared_ptr_HybridIssue1439Spec_(newCxxPart) + return newCxxPart + } + } + + + + /** + * Get the memory size of the Swift class (plus size of any other allocations) + * so the JS VM can properly track it and garbage-collect the JS object if needed. + */ + @inline(__always) + public var memorySize: Int { + return MemoryHelper.getSizeOf(self.__implementation) + self.__implementation.memorySize + } + + /** + * Compares this object with the given [other] object for reference equality. + */ + @inline(__always) + public func equals(other: HybridIssue1439Spec_cxx) -> Bool { + return self.__implementation === other.__implementation + } + + /** + * Call dispose() on the Swift class. + * This _may_ be called manually from JS. + */ + @inline(__always) + public func dispose() { + self.__implementation.dispose() + } + + /** + * Call toString() on the Swift class. + */ + @inline(__always) + public func toString() -> String { + return self.__implementation.toString() + } + + // Properties + + + // Methods + @inline(__always) + public final func callFnTwiceFirstThrows(params: Issue1439Params) -> bridge.Result_std__shared_ptr_Promise_std__string___ { + do { + let __result = try self.__implementation.callFnTwiceFirstThrows(params: params) + let __resultCpp = { () -> bridge.std__shared_ptr_Promise_std__string__ in + let __promise = bridge.create_std__shared_ptr_Promise_std__string__() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__string__(__promise) + __result + .then({ __result in __promiseHolder.resolve(std.string(__result)) }) + .catch({ __error in __promiseHolder.reject(__error.toCpp()) }) + return __promise + }() + return bridge.create_Result_std__shared_ptr_Promise_std__string___(__resultCpp) + } catch (let __error) { + let __exceptionPtr = __error.toCpp() + return bridge.create_Result_std__shared_ptr_Promise_std__string___(__exceptionPtr) + } + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Issue1439CallInput.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Issue1439CallInput.swift new file mode 100644 index 0000000000..ac73560f11 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Issue1439CallInput.swift @@ -0,0 +1,29 @@ +/// +/// Issue1439CallInput.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Represents an instance of `Issue1439CallInput`, backed by a C++ struct. + */ +public typealias Issue1439CallInput = margelo.nitro.test.Issue1439CallInput + +public extension Issue1439CallInput { + private typealias bridge = margelo.nitro.test.bridge.swift + + /** + * Create a new instance of `Issue1439CallInput`. + */ + init(value: String) { + self.init(std.string(value)) + } + + @inline(__always) + var value: String { + return String(self.__value) + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Issue1439Params.swift b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Issue1439Params.swift new file mode 100644 index 0000000000..6d62929ee1 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/ios/swift/Issue1439Params.swift @@ -0,0 +1,58 @@ +/// +/// Issue1439Params.swift +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +import NitroModules + +/** + * Represents an instance of `Issue1439Params`, backed by a C++ struct. + */ +public typealias Issue1439Params = margelo.nitro.test.Issue1439Params + +public extension Issue1439Params { + private typealias bridge = margelo.nitro.test.bridge.swift + + /** + * Create a new instance of `Issue1439Params`. + */ + init(fn: @escaping (_ input: Issue1439CallInput) -> Promise>) { + self.init({ () -> bridge.Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput in + let __closureWrapper = Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput(fn) + return bridge.create_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput(__closureWrapper.toUnsafe()) + }()) + } + + @inline(__always) + var fn: (_ input: Issue1439CallInput) -> Promise> { + return { () -> (Issue1439CallInput) -> Promise> in + let __wrappedFunction = bridge.wrap_Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string_____Issue1439CallInput(self.__fn) + return { (__input: Issue1439CallInput) -> Promise> in + let __result = __wrappedFunction.call(__input) + return { () -> Promise> in + let __promise = Promise>() + let __resolver = { (__result: Promise) in + __promise.resolve(withResult: __result) + } + let __rejecter = { (__error: Error) in + __promise.reject(withError: __error) + } + let __resolverCpp = { () -> bridge.Func_void_std__shared_ptr_Promise_std__string__ in + let __closureWrapper = Func_void_std__shared_ptr_Promise_std__string__(__resolver) + return bridge.create_Func_void_std__shared_ptr_Promise_std__string__(__closureWrapper.toUnsafe()) + }() + let __rejecterCpp = { () -> bridge.Func_void_std__exception_ptr in + let __closureWrapper = Func_void_std__exception_ptr(__rejecter) + return bridge.create_Func_void_std__exception_ptr(__closureWrapper.toUnsafe()) + }() + let __promiseHolder = bridge.wrap_std__shared_ptr_Promise_std__shared_ptr_Promise_std__string____(__result) + __promiseHolder.addOnResolvedListener(__resolverCpp) + __promiseHolder.addOnRejectedListener(__rejecterCpp) + return __promise + }() + } + }() + } +} diff --git a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridIssue1439Spec.cpp b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridIssue1439Spec.cpp new file mode 100644 index 0000000000..e32c882a15 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridIssue1439Spec.cpp @@ -0,0 +1,21 @@ +/// +/// HybridIssue1439Spec.cpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#include "HybridIssue1439Spec.hpp" + +namespace margelo::nitro::test { + + void HybridIssue1439Spec::loadHybridMethods() { + // load base methods/properties + HybridObject::loadHybridMethods(); + // load custom methods/properties + registerHybrids(this, [](Prototype& prototype) { + prototype.registerHybridMethod("callFnTwiceFirstThrows", &HybridIssue1439Spec::callFnTwiceFirstThrows); + }); + } + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridIssue1439Spec.hpp b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridIssue1439Spec.hpp new file mode 100644 index 0000000000..ab5bc083d9 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/HybridIssue1439Spec.hpp @@ -0,0 +1,65 @@ +/// +/// HybridIssue1439Spec.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `Issue1439Params` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439Params; } + +#include +#include +#include "Issue1439Params.hpp" + +namespace margelo::nitro::test { + + using namespace margelo::nitro; + + /** + * An abstract base class for `Issue1439` + * Inherit this class to create instances of `HybridIssue1439Spec` in C++. + * You must explicitly call `HybridObject`'s constructor yourself, because it is virtual. + * @example + * ```cpp + * class HybridIssue1439: public HybridIssue1439Spec { + * public: + * HybridIssue1439(...): HybridObject(TAG) { ... } + * // ... + * }; + * ``` + */ + class HybridIssue1439Spec: public virtual HybridObject { + public: + // Constructor + explicit HybridIssue1439Spec(): HybridObject(TAG) { } + + // Destructor + ~HybridIssue1439Spec() override = default; + + public: + // Properties + + + public: + // Methods + virtual std::shared_ptr> callFnTwiceFirstThrows(const Issue1439Params& params) = 0; + + protected: + // Hybrid Setup + void loadHybridMethods() override; + + protected: + // Tag for logging + static constexpr auto TAG = "Issue1439"; + }; + +} // namespace margelo::nitro::test diff --git a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/Issue1439CallInput.hpp b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/Issue1439CallInput.hpp new file mode 100644 index 0000000000..6eb3049a5d --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/Issue1439CallInput.hpp @@ -0,0 +1,83 @@ +/// +/// Issue1439CallInput.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + + + +#include + +namespace margelo::nitro::test { + + /** + * A struct which can be represented as a JavaScript object (Issue1439CallInput). + */ + struct Issue1439CallInput final { + public: + std::string value SWIFT_PRIVATE; + + public: + Issue1439CallInput() = default; + explicit Issue1439CallInput(std::string value): value(value) {} + + public: + friend bool operator==(const Issue1439CallInput& lhs, const Issue1439CallInput& rhs) = default; + }; + +} // namespace margelo::nitro::test + +namespace margelo::nitro { + + // C++ Issue1439CallInput <> JS Issue1439CallInput (object) + template <> + struct JSIConverter final { + static inline margelo::nitro::test::Issue1439CallInput fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return margelo::nitro::test::Issue1439CallInput( + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "value"))) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::test::Issue1439CallInput& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "value"), JSIConverter::toJSI(runtime, arg.value)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!nitro::isPlainObject(runtime, obj)) { + return false; + } + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "value")))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-nitro-test/nitrogen/generated/shared/c++/Issue1439Params.hpp b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/Issue1439Params.hpp new file mode 100644 index 0000000000..3cae84e592 --- /dev/null +++ b/packages/react-native-nitro-test/nitrogen/generated/shared/c++/Issue1439Params.hpp @@ -0,0 +1,87 @@ +/// +/// Issue1439Params.hpp +/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE. +/// https://github.com/mrousavy/nitro +/// Copyright © Marc Rousavy @ Margelo +/// + +#pragma once + +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif +#if __has_include() +#include +#else +#error NitroModules cannot be found! Are you sure you installed NitroModules properly? +#endif + +// Forward declaration of `Issue1439CallInput` to properly resolve imports. +namespace margelo::nitro::test { struct Issue1439CallInput; } + +#include +#include +#include "Issue1439CallInput.hpp" +#include + +namespace margelo::nitro::test { + + /** + * A struct which can be represented as a JavaScript object (Issue1439Params). + */ + struct Issue1439Params final { + public: + std::function>>>(const Issue1439CallInput& /* input */)> fn SWIFT_PRIVATE; + + public: + Issue1439Params() = default; + explicit Issue1439Params(std::function>>>(const Issue1439CallInput& /* input */)> fn): fn(fn) {} + + public: + // Issue1439Params is not equatable because these properties are not equatable: fn + }; + +} // namespace margelo::nitro::test + +namespace margelo::nitro { + + // C++ Issue1439Params <> JS Issue1439Params (object) + template <> + struct JSIConverter final { + static inline margelo::nitro::test::Issue1439Params fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { + jsi::Object obj = arg.asObject(runtime); + return margelo::nitro::test::Issue1439Params( + JSIConverter>>>(const margelo::nitro::test::Issue1439CallInput&)>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "fn"))) + ); + } + static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::test::Issue1439Params& arg) { + jsi::Object obj(runtime); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "fn"), JSIConverter>>>(const margelo::nitro::test::Issue1439CallInput&)>>::toJSI(runtime, arg.fn)); + return obj; + } + static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { + if (!value.isObject()) { + return false; + } + jsi::Object obj = value.getObject(runtime); + if (!nitro::isPlainObject(runtime, obj)) { + return false; + } + if (!JSIConverter>>>(const margelo::nitro::test::Issue1439CallInput&)>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "fn")))) return false; + return true; + } + }; + +} // namespace margelo::nitro diff --git a/packages/react-native-nitro-test/src/index.ts b/packages/react-native-nitro-test/src/index.ts index 6d4b6070d4..647ffb41cd 100644 --- a/packages/react-native-nitro-test/src/index.ts +++ b/packages/react-native-nitro-test/src/index.ts @@ -6,10 +6,12 @@ import { import { type PlatformObject } from './specs/PlatformObject.nitro' import type { Base } from './specs/Base.nitro' import type { Child } from './specs/Child.nitro' +import type { Issue1439 } from './specs/Issue1439.nitro' // Export all Hybrid Object types export * from './specs/Base.nitro' export * from './specs/Child.nitro' +export * from './specs/Issue1439.nitro' export * from './specs/PlatformObject.nitro' export * from './specs/TestObject.nitro' export * from './specs/TestView.nitro' @@ -26,6 +28,9 @@ export const HybridChild = NitroModules.createHybridObject('Child') export const HybridPlatformObject = NitroModules.createHybridObject('PlatformObject') +export const HybridIssue1439 = + NitroModules.createHybridObject('Issue1439') + // Export View (+ its ref type) export { TestView, type TestViewRef } from './views/TestView' export { diff --git a/packages/react-native-nitro-test/src/specs/Issue1439.nitro.ts b/packages/react-native-nitro-test/src/specs/Issue1439.nitro.ts new file mode 100644 index 0000000000..14e41760a0 --- /dev/null +++ b/packages/react-native-nitro-test/src/specs/Issue1439.nitro.ts @@ -0,0 +1,34 @@ +import { type HybridObject } from 'react-native-nitro-modules' + +/** + * Input passed to the JS callback from native code. + */ +export type Issue1439CallInput = { + value: string +} + +/** + * Params struct that wraps the JS callback, mirroring the HybridRemoteClientCallHandlerParams + * pattern from the real-world use case described in issue #1439. + */ +export type Issue1439Params = { + fn: (input: Issue1439CallInput) => Promise +} + +/** + * Reproduces issue #1439: + * https://github.com/mrousavy/nitro/issues/1439 + * + * A JS async function is passed inside a struct to native code. + * Native invokes it twice from a background thread: + * - First invocation: the JS function throws an error + * - Second invocation: should succeed, but hangs forever + */ +export interface Issue1439 extends HybridObject<{ ios: 'swift'; android: 'kotlin' }> { + /** + * Calls `params.fn` twice from a native background thread. + * The first call is expected to throw; the second should return "second". + * Returns the result of the second call. + */ + callFnTwiceFirstThrows(params: Issue1439Params): Promise +} diff --git a/run-android-tests.sh b/run-android-tests.sh new file mode 100755 index 0000000000..aabde86df6 --- /dev/null +++ b/run-android-tests.sh @@ -0,0 +1,146 @@ +#!/usr/bin/env bash +# run-android-tests.sh +# Builds the Android app and runs the react-native-harness test suite. +# Usage: ./run-android-tests.sh [AVD_NAME] [API_LEVEL] [DEVICE_PROFILE] + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EXAMPLE_DIR="$SCRIPT_DIR/example" +ANDROID_DIR="$EXAMPLE_DIR/android" + +# ─── Defaults (override via positional args or env vars) ─────────────────────── +AVD_NAME="${1:-${AVD_NAME:-Pixel_8_API_35}}" +DEVICE_API_LEVEL="${2:-${DEVICE_API_LEVEL:-35}}" +DEVICE_PROFILE="${3:-${DEVICE_PROFILE:-pixel_8}}" + +JAVA_HOME_OVERRIDE="${JAVA_HOME_OVERRIDE:-/usr/lib/jvm/java-17-temurin-jdk}" + +# Detect architecture from the running emulator; fall back to x86_64 +detect_abi() { + local abi + abi=$(adb shell getprop ro.product.cpu.abi 2>/dev/null | tr -d '\r') + case "$abi" in + arm64-v8a|armeabi-v7a|x86_64|x86) echo "$abi" ;; + *) echo "x86_64" ;; + esac +} + +# ─── Check prerequisites ─────────────────────────────────────────────────────── +echo "==> Checking prerequisites..." + +if ! command -v adb &>/dev/null; then + echo "ERROR: adb not found. Install Android SDK platform-tools." >&2 + exit 1 +fi + +if ! command -v npx &>/dev/null; then + echo "ERROR: npx not found. Install Node.js." >&2 + exit 1 +fi + +if [ ! -d "$JAVA_HOME_OVERRIDE" ]; then + echo "WARNING: Java 17 not found at $JAVA_HOME_OVERRIDE — using system Java (may fail)." + JAVA_HOME_OVERRIDE="" +fi + +# ─── Verify emulator is running ─────────────────────────────────────────────── +echo "==> Checking for connected Android device/emulator..." +if ! adb devices | grep -q "device$"; then + echo "ERROR: No device/emulator connected. Start an emulator first." >&2 + exit 1 +fi + +ABI=$(detect_abi) +echo " Device ABI: $ABI" +echo " AVD_NAME: $AVD_NAME" +echo " API_LEVEL: $DEVICE_API_LEVEL" +echo " PROFILE: $DEVICE_PROFILE" + +# ─── Build ──────────────────────────────────────────────────────────────────── +echo "" +echo "==> Building Android app (arch: $ABI)..." + +BUILD_ENV=() +if [ -n "$JAVA_HOME_OVERRIDE" ]; then + BUILD_ENV+=( + "JAVA_HOME=$JAVA_HOME_OVERRIDE" + "PATH=$JAVA_HOME_OVERRIDE/bin:$PATH" + ) +fi + +env "${BUILD_ENV[@]}" \ + "$ANDROID_DIR/gradlew" \ + -p "$ANDROID_DIR" \ + assembleDebug \ + --no-daemon \ + --console=plain \ + "-PreactNativeArchitectures=$ABI" + +APK="$ANDROID_DIR/app/build/outputs/apk/debug/app-debug.apk" +if [ ! -f "$APK" ]; then + echo "ERROR: APK not found at $APK" >&2 + exit 1 +fi + +# ─── Install ────────────────────────────────────────────────────────────────── +echo "" +echo "==> Installing APK on device..." +adb install -r "$APK" + +# ─── Start Metro (if not already running) ───────────────────────────────────── +METRO_PORT=8081 +if curl -sf "http://localhost:$METRO_PORT/status" &>/dev/null; then + echo "" + echo "==> Metro already running on port $METRO_PORT." + METRO_PID="" +else + echo "" + echo "==> Starting Metro bundler..." + cd "$EXAMPLE_DIR" + npx react-native start --no-interactive & + METRO_PID=$! + + echo " Waiting for Metro to be ready..." + for i in $(seq 1 30); do + if curl -sf "http://localhost:$METRO_PORT/status" &>/dev/null; then + echo " Metro ready." + break + fi + sleep 2 + if [ "$i" -eq 30 ]; then + echo "ERROR: Metro did not start in time." >&2 + kill "$METRO_PID" 2>/dev/null || true + exit 1 + fi + done +fi + +# ─── Run tests ──────────────────────────────────────────────────────────────── +echo "" +echo "==> Running harness tests..." +cd "$EXAMPLE_DIR" + +set +e +AVD_NAME="$AVD_NAME" \ +DEVICE_API_LEVEL="$DEVICE_API_LEVEL" \ +DEVICE_PROFILE="$DEVICE_PROFILE" \ + npx react-native-harness +TEST_EXIT=$? +set -e + +# ─── Cleanup ────────────────────────────────────────────────────────────────── +if [ -n "${METRO_PID:-}" ]; then + echo "" + echo "==> Stopping Metro (PID $METRO_PID)..." + kill "$METRO_PID" 2>/dev/null || true +fi + +echo "" +if [ "$TEST_EXIT" -eq 0 ]; then + echo "✅ All tests passed." +else + echo "❌ Some tests failed (exit code $TEST_EXIT)." +fi + +exit "$TEST_EXIT"