expo-modules-core 2.3.8 → 2.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/android/build.gradle +22 -9
- package/android/src/compose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt +35 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +2 -2
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +17 -17
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionComponent.kt +75 -68
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionWithPromiseComponent.kt +1 -1
- package/android/src/main/java/expo/modules/kotlin/functions/UntypedAsyncFunctionComponent.kt +84 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +8 -25
- package/android/src/main/java/expo/modules/kotlin/objects/ObjectDefinitionBuilder.kt +19 -19
- package/android/src/main/java/expo/modules/kotlin/views/ViewDefinitionBuilder.kt +19 -19
- package/android/src/withoutCompose/expo/modules/kotlin/views/ModuleDefinitionBuilderComposeExtension.kt +10 -0
- package/common/cpp/TestingSyncJSCallInvoker.h +0 -10
- package/ios/Api/Builders/ViewDefinitionBuilder.swift +5 -0
- package/ios/Core/Functions/AsyncFunctionDefinition.swift +1 -0
- package/ios/Core/Functions/ConcurrentFunctionDefinition.swift +20 -2
- package/ios/Core/Promise.swift +8 -6
- package/ios/Core/Views/SwiftUI/SwiftUIViewDefinition.swift +2 -1
- package/ios/Core/Views/SwiftUI/SwiftUIViewDefinitionBuilder.swift +5 -0
- package/ios/JSI/EXJSIConversions.mm +4 -0
- package/ios/JSI/EXJavaScriptRuntime.mm +2 -2
- package/ios/JSI/EXJavaScriptSharedObjectBinding.h +25 -0
- package/ios/JSI/EXJavaScriptSharedObjectBinding.mm +24 -0
- package/ios/TestUtils/MainThreadInvoker.h +14 -0
- package/ios/TestUtils/MainThreadInvoker.mm +19 -0
- package/ios/TestUtils/TestingJSCallInvoker.h +46 -0
- package/ios/Tests/FunctionSpec.swift +18 -6
- package/package.json +3 -3
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunction.kt +0 -91
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/AutoSizingComposable.kt +0 -0
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ComposeProps.kt +0 -0
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ComposeViewProp.kt +0 -0
- /package/android/src/{main/java → compose}/expo/modules/kotlin/views/ExpoComposeView.kt +0 -0
|
@@ -8,7 +8,7 @@ import expo.modules.kotlin.component6
|
|
|
8
8
|
import expo.modules.kotlin.component7
|
|
9
9
|
import expo.modules.kotlin.component8
|
|
10
10
|
import expo.modules.kotlin.events.EventsDefinition
|
|
11
|
-
import expo.modules.kotlin.functions.
|
|
11
|
+
import expo.modules.kotlin.functions.AsyncFunctionComponent
|
|
12
12
|
import expo.modules.kotlin.functions.AsyncFunctionBuilder
|
|
13
13
|
import expo.modules.kotlin.functions.AsyncFunctionWithPromiseComponent
|
|
14
14
|
import expo.modules.kotlin.functions.FunctionBuilder
|
|
@@ -47,7 +47,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
47
47
|
internal var syncFunctionBuilder = mutableMapOf<String, FunctionBuilder>()
|
|
48
48
|
|
|
49
49
|
@PublishedApi
|
|
50
|
-
internal var asyncFunctions = mutableMapOf<String,
|
|
50
|
+
internal var asyncFunctions = mutableMapOf<String, AsyncFunctionComponent>()
|
|
51
51
|
|
|
52
52
|
private var asyncFunctionBuilders = mutableMapOf<String, AsyncFunctionBuilder>()
|
|
53
53
|
|
|
@@ -222,7 +222,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
222
222
|
inline fun AsyncFunction(
|
|
223
223
|
name: String,
|
|
224
224
|
crossinline body: () -> Any?
|
|
225
|
-
):
|
|
225
|
+
): AsyncFunctionComponent {
|
|
226
226
|
return createAsyncFunctionComponent(name, emptyArray()) { body() }.also {
|
|
227
227
|
asyncFunctions[name] = it
|
|
228
228
|
}
|
|
@@ -231,7 +231,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
231
231
|
inline fun <reified R> AsyncFunction(
|
|
232
232
|
name: String,
|
|
233
233
|
crossinline body: () -> R
|
|
234
|
-
):
|
|
234
|
+
): AsyncFunctionComponent {
|
|
235
235
|
return createAsyncFunctionComponent(name, emptyArray()) { body() }.also {
|
|
236
236
|
asyncFunctions[name] = it
|
|
237
237
|
}
|
|
@@ -240,7 +240,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
240
240
|
inline fun <reified R, reified P0> AsyncFunction(
|
|
241
241
|
name: String,
|
|
242
242
|
crossinline body: (p0: P0) -> R
|
|
243
|
-
):
|
|
243
|
+
): AsyncFunctionComponent {
|
|
244
244
|
// We can't split that function, because that introduces a ambiguity when creating DSL component without parameters.
|
|
245
245
|
return if (P0::class.java == Promise::class.java) {
|
|
246
246
|
AsyncFunctionWithPromiseComponent(name, arrayOf()) { _, promise -> body(promise as P0) }
|
|
@@ -257,7 +257,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
257
257
|
inline fun <reified R, reified P0, reified P1> AsyncFunction(
|
|
258
258
|
name: String,
|
|
259
259
|
crossinline body: (p0: P0, p1: P1) -> R
|
|
260
|
-
):
|
|
260
|
+
): AsyncFunctionComponent {
|
|
261
261
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1>()) { (p0, p1) ->
|
|
262
262
|
enforceType<P0, P1>(p0, p1)
|
|
263
263
|
body(p0, p1)
|
|
@@ -270,7 +270,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
270
270
|
inline fun <reified R, reified P0> AsyncFunction(
|
|
271
271
|
name: String,
|
|
272
272
|
crossinline body: (p0: P0, p1: Promise) -> R
|
|
273
|
-
):
|
|
273
|
+
): AsyncFunctionComponent {
|
|
274
274
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>()) { (p0), promise ->
|
|
275
275
|
enforceType<P0>(p0)
|
|
276
276
|
body(p0, promise)
|
|
@@ -282,7 +282,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
282
282
|
inline fun <reified R, reified P0, reified P1, reified P2> AsyncFunction(
|
|
283
283
|
name: String,
|
|
284
284
|
crossinline body: (p0: P0, p1: P1, p2: P2) -> R
|
|
285
|
-
):
|
|
285
|
+
): AsyncFunctionComponent {
|
|
286
286
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2) ->
|
|
287
287
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
288
288
|
body(p0, p1, p2)
|
|
@@ -295,7 +295,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
295
295
|
inline fun <reified R, reified P0, reified P1> AsyncFunction(
|
|
296
296
|
name: String,
|
|
297
297
|
crossinline body: (p0: P0, p1: P1, p2: Promise) -> R
|
|
298
|
-
):
|
|
298
|
+
): AsyncFunctionComponent {
|
|
299
299
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>()) { (p0, p1), promise ->
|
|
300
300
|
enforceType<P0, P1>(p0, p1)
|
|
301
301
|
body(p0, p1, promise)
|
|
@@ -307,7 +307,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
307
307
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncFunction(
|
|
308
308
|
name: String,
|
|
309
309
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
|
|
310
|
-
):
|
|
310
|
+
): AsyncFunctionComponent {
|
|
311
311
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3) ->
|
|
312
312
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
313
313
|
body(p0, p1, p2, p3)
|
|
@@ -320,7 +320,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
320
320
|
inline fun <reified R, reified P0, reified P1, reified P2> AsyncFunction(
|
|
321
321
|
name: String,
|
|
322
322
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: Promise) -> R
|
|
323
|
-
):
|
|
323
|
+
): AsyncFunctionComponent {
|
|
324
324
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2), promise ->
|
|
325
325
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
326
326
|
body(p0, p1, p2, promise)
|
|
@@ -332,7 +332,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
332
332
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncFunction(
|
|
333
333
|
name: String,
|
|
334
334
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
|
|
335
|
-
):
|
|
335
|
+
): AsyncFunctionComponent {
|
|
336
336
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4) ->
|
|
337
337
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
338
338
|
body(p0, p1, p2, p3, p4)
|
|
@@ -345,7 +345,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
345
345
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncFunction(
|
|
346
346
|
name: String,
|
|
347
347
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: Promise) -> R
|
|
348
|
-
):
|
|
348
|
+
): AsyncFunctionComponent {
|
|
349
349
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3), promise ->
|
|
350
350
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
351
351
|
body(p0, p1, p2, p3, promise)
|
|
@@ -357,7 +357,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
357
357
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncFunction(
|
|
358
358
|
name: String,
|
|
359
359
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
|
|
360
|
-
):
|
|
360
|
+
): AsyncFunctionComponent {
|
|
361
361
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5) ->
|
|
362
362
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
363
363
|
body(p0, p1, p2, p3, p4, p5)
|
|
@@ -370,7 +370,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
370
370
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncFunction(
|
|
371
371
|
name: String,
|
|
372
372
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: Promise) -> R
|
|
373
|
-
):
|
|
373
|
+
): AsyncFunctionComponent {
|
|
374
374
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4), promise ->
|
|
375
375
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
376
376
|
body(p0, p1, p2, p3, p4, promise)
|
|
@@ -382,7 +382,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
382
382
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncFunction(
|
|
383
383
|
name: String,
|
|
384
384
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
|
|
385
|
-
):
|
|
385
|
+
): AsyncFunctionComponent {
|
|
386
386
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6) ->
|
|
387
387
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
388
388
|
body(p0, p1, p2, p3, p4, p5, p6)
|
|
@@ -395,7 +395,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
395
395
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncFunction(
|
|
396
396
|
name: String,
|
|
397
397
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: Promise) -> R
|
|
398
|
-
):
|
|
398
|
+
): AsyncFunctionComponent {
|
|
399
399
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5), promise ->
|
|
400
400
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
401
401
|
body(p0, p1, p2, p3, p4, p5, promise)
|
|
@@ -407,7 +407,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
407
407
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> AsyncFunction(
|
|
408
408
|
name: String,
|
|
409
409
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
|
|
410
|
-
):
|
|
410
|
+
): AsyncFunctionComponent {
|
|
411
411
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
|
|
412
412
|
enforceType<P0, P1, P2, P3, P4, P5, P6, P7>(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
413
413
|
body(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
@@ -420,7 +420,7 @@ open class ObjectDefinitionBuilder(customConverter: TypeConverterProvider? = nul
|
|
|
420
420
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncFunction(
|
|
421
421
|
name: String,
|
|
422
422
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: Promise) -> R
|
|
423
|
-
):
|
|
423
|
+
): AsyncFunctionComponent {
|
|
424
424
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6), promise ->
|
|
425
425
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
426
426
|
body(p0, p1, p2, p3, p4, p5, p6, promise)
|
|
@@ -13,7 +13,7 @@ import expo.modules.kotlin.component7
|
|
|
13
13
|
import expo.modules.kotlin.component8
|
|
14
14
|
import expo.modules.kotlin.exception.CodedException
|
|
15
15
|
import expo.modules.kotlin.exception.UnexpectedException
|
|
16
|
-
import expo.modules.kotlin.functions.
|
|
16
|
+
import expo.modules.kotlin.functions.AsyncFunctionComponent
|
|
17
17
|
import expo.modules.kotlin.functions.AsyncFunctionBuilder
|
|
18
18
|
import expo.modules.kotlin.functions.AsyncFunctionWithPromiseComponent
|
|
19
19
|
import expo.modules.kotlin.functions.Queues
|
|
@@ -47,7 +47,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
47
47
|
private var callbacksDefinition: CallbacksDefinition? = null
|
|
48
48
|
|
|
49
49
|
@PublishedApi
|
|
50
|
-
internal var asyncFunctions = mutableMapOf<String,
|
|
50
|
+
internal var asyncFunctions = mutableMapOf<String, AsyncFunctionComponent>()
|
|
51
51
|
|
|
52
52
|
private var functionBuilders = mutableMapOf<String, AsyncFunctionBuilder>()
|
|
53
53
|
|
|
@@ -193,7 +193,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
193
193
|
inline fun AsyncFunction(
|
|
194
194
|
name: String,
|
|
195
195
|
crossinline body: () -> Any?
|
|
196
|
-
):
|
|
196
|
+
): AsyncFunctionComponent {
|
|
197
197
|
return createAsyncFunctionComponent(name, emptyArray()) { body() }.also {
|
|
198
198
|
asyncFunctions[name] = it
|
|
199
199
|
}
|
|
@@ -202,7 +202,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
202
202
|
inline fun <reified R> AsyncFunction(
|
|
203
203
|
name: String,
|
|
204
204
|
crossinline body: () -> R
|
|
205
|
-
):
|
|
205
|
+
): AsyncFunctionComponent {
|
|
206
206
|
return createAsyncFunctionComponent(name, emptyArray()) { body() }.also {
|
|
207
207
|
asyncFunctions[name] = it
|
|
208
208
|
}
|
|
@@ -211,7 +211,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
211
211
|
inline fun <reified R, reified P0> AsyncFunction(
|
|
212
212
|
name: String,
|
|
213
213
|
crossinline body: (p0: P0) -> R
|
|
214
|
-
):
|
|
214
|
+
): AsyncFunctionComponent {
|
|
215
215
|
// We can't split that function, because that introduces a ambiguity when creating DSL component without parameters.
|
|
216
216
|
return if (P0::class == Promise::class) {
|
|
217
217
|
AsyncFunctionWithPromiseComponent(name, emptyArray()) { _, promise -> body(promise as P0) }
|
|
@@ -228,7 +228,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
228
228
|
inline fun <reified R, reified P0, reified P1> AsyncFunction(
|
|
229
229
|
name: String,
|
|
230
230
|
crossinline body: (p0: P0, p1: P1) -> R
|
|
231
|
-
):
|
|
231
|
+
): AsyncFunctionComponent {
|
|
232
232
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1>()) { (p0, p1) ->
|
|
233
233
|
enforceType<P0, P1>(p0, p1)
|
|
234
234
|
body(p0, p1)
|
|
@@ -241,7 +241,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
241
241
|
inline fun <reified R, reified P0> AsyncFunction(
|
|
242
242
|
name: String,
|
|
243
243
|
crossinline body: (p0: P0, p1: Promise) -> R
|
|
244
|
-
):
|
|
244
|
+
): AsyncFunctionComponent {
|
|
245
245
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0>()) { (p0), promise ->
|
|
246
246
|
enforceType<P0>(p0)
|
|
247
247
|
body(p0, promise)
|
|
@@ -253,7 +253,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
253
253
|
inline fun <reified R, reified P0, reified P1, reified P2> AsyncFunction(
|
|
254
254
|
name: String,
|
|
255
255
|
crossinline body: (p0: P0, p1: P1, p2: P2) -> R
|
|
256
|
-
):
|
|
256
|
+
): AsyncFunctionComponent {
|
|
257
257
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2) ->
|
|
258
258
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
259
259
|
body(p0, p1, p2)
|
|
@@ -266,7 +266,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
266
266
|
inline fun <reified R, reified P0, reified P1> AsyncFunction(
|
|
267
267
|
name: String,
|
|
268
268
|
crossinline body: (p0: P0, p1: P1, p2: Promise) -> R
|
|
269
|
-
):
|
|
269
|
+
): AsyncFunctionComponent {
|
|
270
270
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1>()) { (p0, p1), promise ->
|
|
271
271
|
enforceType<P0, P1>(p0, p1)
|
|
272
272
|
body(p0, p1, promise)
|
|
@@ -278,7 +278,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
278
278
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncFunction(
|
|
279
279
|
name: String,
|
|
280
280
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3) -> R
|
|
281
|
-
):
|
|
281
|
+
): AsyncFunctionComponent {
|
|
282
282
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3) ->
|
|
283
283
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
284
284
|
body(p0, p1, p2, p3)
|
|
@@ -291,7 +291,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
291
291
|
inline fun <reified R, reified P0, reified P1, reified P2> AsyncFunction(
|
|
292
292
|
name: String,
|
|
293
293
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: Promise) -> R
|
|
294
|
-
):
|
|
294
|
+
): AsyncFunctionComponent {
|
|
295
295
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2>()) { (p0, p1, p2), promise ->
|
|
296
296
|
enforceType<P0, P1, P2>(p0, p1, p2)
|
|
297
297
|
body(p0, p1, p2, promise)
|
|
@@ -303,7 +303,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
303
303
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncFunction(
|
|
304
304
|
name: String,
|
|
305
305
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4) -> R
|
|
306
|
-
):
|
|
306
|
+
): AsyncFunctionComponent {
|
|
307
307
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4) ->
|
|
308
308
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
309
309
|
body(p0, p1, p2, p3, p4)
|
|
@@ -316,7 +316,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
316
316
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3> AsyncFunction(
|
|
317
317
|
name: String,
|
|
318
318
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: Promise) -> R
|
|
319
|
-
):
|
|
319
|
+
): AsyncFunctionComponent {
|
|
320
320
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3>()) { (p0, p1, p2, p3), promise ->
|
|
321
321
|
enforceType<P0, P1, P2, P3>(p0, p1, p2, p3)
|
|
322
322
|
body(p0, p1, p2, p3, promise)
|
|
@@ -328,7 +328,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
328
328
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncFunction(
|
|
329
329
|
name: String,
|
|
330
330
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5) -> R
|
|
331
|
-
):
|
|
331
|
+
): AsyncFunctionComponent {
|
|
332
332
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5) ->
|
|
333
333
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
334
334
|
body(p0, p1, p2, p3, p4, p5)
|
|
@@ -341,7 +341,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
341
341
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4> AsyncFunction(
|
|
342
342
|
name: String,
|
|
343
343
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: Promise) -> R
|
|
344
|
-
):
|
|
344
|
+
): AsyncFunctionComponent {
|
|
345
345
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4>()) { (p0, p1, p2, p3, p4), promise ->
|
|
346
346
|
enforceType<P0, P1, P2, P3, P4>(p0, p1, p2, p3, p4)
|
|
347
347
|
body(p0, p1, p2, p3, p4, promise)
|
|
@@ -353,7 +353,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
353
353
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncFunction(
|
|
354
354
|
name: String,
|
|
355
355
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6) -> R
|
|
356
|
-
):
|
|
356
|
+
): AsyncFunctionComponent {
|
|
357
357
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6) ->
|
|
358
358
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
359
359
|
body(p0, p1, p2, p3, p4, p5, p6)
|
|
@@ -366,7 +366,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
366
366
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5> AsyncFunction(
|
|
367
367
|
name: String,
|
|
368
368
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: Promise) -> R
|
|
369
|
-
):
|
|
369
|
+
): AsyncFunctionComponent {
|
|
370
370
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5>()) { (p0, p1, p2, p3, p4, p5), promise ->
|
|
371
371
|
enforceType<P0, P1, P2, P3, P4, P5>(p0, p1, p2, p3, p4, p5)
|
|
372
372
|
body(p0, p1, p2, p3, p4, p5, promise)
|
|
@@ -378,7 +378,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
378
378
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6, reified P7> AsyncFunction(
|
|
379
379
|
name: String,
|
|
380
380
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7) -> R
|
|
381
|
-
):
|
|
381
|
+
): AsyncFunctionComponent {
|
|
382
382
|
return createAsyncFunctionComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6, P7>()) { (p0, p1, p2, p3, p4, p5, p6, p7) ->
|
|
383
383
|
enforceType<P0, P1, P2, P3, P4, P5, P6, P7>(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
384
384
|
body(p0, p1, p2, p3, p4, p5, p6, p7)
|
|
@@ -391,7 +391,7 @@ class ViewDefinitionBuilder<T : View>(
|
|
|
391
391
|
inline fun <reified R, reified P0, reified P1, reified P2, reified P3, reified P4, reified P5, reified P6> AsyncFunction(
|
|
392
392
|
name: String,
|
|
393
393
|
crossinline body: (p0: P0, p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: Promise) -> R
|
|
394
|
-
):
|
|
394
|
+
): AsyncFunctionComponent {
|
|
395
395
|
return AsyncFunctionWithPromiseComponent(name, toArgsArray<P0, P1, P2, P3, P4, P5, P6>()) { (p0, p1, p2, p3, p4, p5, p6), promise ->
|
|
396
396
|
enforceType<P0, P1, P2, P3, P4, P5, P6>(p0, p1, p2, p3, p4, p5, p6)
|
|
397
397
|
body(p0, p1, p2, p3, p4, p5, p6, promise)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
@file:Suppress("FunctionName")
|
|
2
|
+
|
|
3
|
+
package expo.modules.kotlin.views
|
|
4
|
+
|
|
5
|
+
import expo.modules.kotlin.modules.InternalModuleDefinitionBuilder
|
|
6
|
+
import expo.modules.kotlin.modules.Module
|
|
7
|
+
|
|
8
|
+
open class ModuleDefinitionBuilderWithCompose(
|
|
9
|
+
module: Module? = null
|
|
10
|
+
) : InternalModuleDefinitionBuilder(module)
|
|
@@ -21,7 +21,6 @@ class TestingSyncJSCallInvoker : public react::CallInvoker {
|
|
|
21
21
|
public:
|
|
22
22
|
explicit TestingSyncJSCallInvoker(const std::shared_ptr<jsi::Runtime>& runtime) : runtime(runtime) {}
|
|
23
23
|
|
|
24
|
-
#if REACT_NATIVE_TARGET_VERSION >= 75
|
|
25
24
|
void invokeAsync(react::CallFunc &&func) noexcept override {
|
|
26
25
|
func(*runtime.lock());
|
|
27
26
|
}
|
|
@@ -29,15 +28,6 @@ public:
|
|
|
29
28
|
void invokeSync(react::CallFunc &&func) override {
|
|
30
29
|
func(*runtime.lock());
|
|
31
30
|
}
|
|
32
|
-
#else
|
|
33
|
-
void invokeAsync(std::function<void()> &&func) noexcept override {
|
|
34
|
-
func();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
void invokeSync(std::function<void()> &&func) override {
|
|
38
|
-
func();
|
|
39
|
-
}
|
|
40
|
-
#endif
|
|
41
31
|
|
|
42
32
|
~TestingSyncJSCallInvoker() override = default;
|
|
43
33
|
|
|
@@ -55,6 +55,11 @@ public struct ViewDefinitionBuilder<ViewType: UIView> {
|
|
|
55
55
|
function.runOnQueue(.main)
|
|
56
56
|
function.takesOwner = true
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
if var function = element as? AnyConcurrentFunctionDefinition {
|
|
60
|
+
function.requiresMainActor = true
|
|
61
|
+
function.takesOwner = true
|
|
62
|
+
}
|
|
58
63
|
return element
|
|
59
64
|
}
|
|
60
65
|
}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
Type-erased protocol for asynchronous functions using Swift concurrency
|
|
5
|
+
*/
|
|
6
|
+
internal protocol AnyConcurrentFunctionDefinition: AnyFunctionDefinition {
|
|
7
|
+
/**
|
|
8
|
+
Specifies if the main actor should be used. Necessary when attached to a view
|
|
9
|
+
*/
|
|
10
|
+
var requiresMainActor: Bool { get set }
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
/**
|
|
4
14
|
Represents a concurrent function that can only be called asynchronously, thus its JavaScript equivalent returns a Promise.
|
|
5
15
|
As opposed to `AsyncFunctionDefinition`, it can leverage the new Swift's concurrency model and take the async/await closure.
|
|
6
16
|
*/
|
|
7
|
-
public final class ConcurrentFunctionDefinition<Args, FirstArgType, ReturnType>:
|
|
17
|
+
public final class ConcurrentFunctionDefinition<Args, FirstArgType, ReturnType>: AnyConcurrentFunctionDefinition {
|
|
8
18
|
typealias ClosureType = (Args) async throws -> ReturnType
|
|
9
19
|
|
|
10
20
|
let body: ClosureType
|
|
@@ -31,6 +41,7 @@ public final class ConcurrentFunctionDefinition<Args, FirstArgType, ReturnType>:
|
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
var takesOwner: Bool = false
|
|
44
|
+
var requiresMainActor: Bool = false
|
|
34
45
|
|
|
35
46
|
func call(by owner: AnyObject?, withArguments args: [Any], appContext: AppContext, callback: @escaping (FunctionCallResult) -> Void) {
|
|
36
47
|
var arguments: [Any]
|
|
@@ -62,7 +73,14 @@ public final class ConcurrentFunctionDefinition<Args, FirstArgType, ReturnType>:
|
|
|
62
73
|
|
|
63
74
|
do {
|
|
64
75
|
// Convert arguments to the types desired by the function.
|
|
65
|
-
|
|
76
|
+
var finalArguments: [Any]
|
|
77
|
+
if requiresMainActor {
|
|
78
|
+
finalArguments = try await MainActor.run {
|
|
79
|
+
try cast(arguments: arguments, forFunction: self, appContext: appContext)
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
finalArguments = try cast(arguments: arguments, forFunction: self, appContext: appContext)
|
|
83
|
+
}
|
|
66
84
|
|
|
67
85
|
// TODO: Right now we force cast the tuple in all types of functions, but we should throw another exception here.
|
|
68
86
|
// swiftlint:disable force_cast
|
package/ios/Core/Promise.swift
CHANGED
|
@@ -20,12 +20,14 @@ public struct Promise: AnyArgument {
|
|
|
20
20
|
|
|
21
21
|
public func resolve(_ value: Any? = nil) {
|
|
22
22
|
if let value = value as? AnySharedObject {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
resolver(JavaScriptSharedObjectBinding.init {
|
|
24
|
+
return Conversions.convertFunctionResult(
|
|
25
|
+
value,
|
|
26
|
+
appContext: appContext,
|
|
27
|
+
dynamicType: type(of: value).getDynamicType()
|
|
28
|
+
// swiftlint:disable:next force_cast
|
|
29
|
+
) as! JavaScriptObject
|
|
30
|
+
})
|
|
29
31
|
return
|
|
30
32
|
}
|
|
31
33
|
resolver(value)
|
|
@@ -19,7 +19,8 @@ public extension ExpoSwiftUIView {
|
|
|
19
19
|
/**
|
|
20
20
|
Returns React's children as SwiftUI views.
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
// swiftlint:disable:next identifier_name
|
|
23
|
+
func Children() -> ForEach<[any ExpoSwiftUI.AnyChild], ObjectIdentifier, AnyView> {
|
|
23
24
|
ForEach(props.children ?? [], id: \.id) { child in
|
|
24
25
|
let view: any View = child.childView
|
|
25
26
|
AnyView(view)
|
|
@@ -30,6 +30,11 @@ extension ExpoSwiftUI {
|
|
|
30
30
|
function.runOnQueue(.main)
|
|
31
31
|
function.takesOwner = true
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
if var function = element as? AnyConcurrentFunctionDefinition {
|
|
35
|
+
function.requiresMainActor = true
|
|
36
|
+
function.takesOwner = true
|
|
37
|
+
}
|
|
33
38
|
return element
|
|
34
39
|
}
|
|
35
40
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#import <ExpoModulesCore/EXJSIConversions.h>
|
|
8
8
|
#import <ExpoModulesCore/EXJavaScriptValue.h>
|
|
9
9
|
#import <ExpoModulesCore/EXJavaScriptRuntime.h>
|
|
10
|
+
#import <ExpoModulesCore/EXJavaScriptSharedObjectBinding.h>
|
|
10
11
|
|
|
11
12
|
namespace expo {
|
|
12
13
|
|
|
@@ -78,6 +79,9 @@ jsi::Value convertObjCObjectToJSIValue(jsi::Runtime &runtime, id value)
|
|
|
78
79
|
if ([value isKindOfClass:[EXJavaScriptWeakObject class]]) {
|
|
79
80
|
return jsi::Value(runtime, *[[(EXJavaScriptWeakObject *)value lock] get]);
|
|
80
81
|
}
|
|
82
|
+
if ([value isKindOfClass:[EXJavaScriptSharedObjectBinding class]]) {
|
|
83
|
+
return jsi::Value(runtime, *[[(EXJavaScriptSharedObjectBinding *)value get] get]);
|
|
84
|
+
}
|
|
81
85
|
if ([value isKindOfClass:[NSString class]]) {
|
|
82
86
|
return convertNSStringToJSIString(runtime, (NSString *)value);
|
|
83
87
|
} else if ([value isKindOfClass:[NSNumber class]]) {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
#import <ExpoModulesCore/EXJSIConversions.h>
|
|
15
15
|
#import <ExpoModulesCore/SharedObject.h>
|
|
16
16
|
#import <ExpoModulesCore/Swift.h>
|
|
17
|
-
#import <ExpoModulesCore/
|
|
17
|
+
#import <ExpoModulesCore/TestingJSCallInvoker.h>
|
|
18
18
|
|
|
19
19
|
@implementation EXJavaScriptRuntime {
|
|
20
20
|
std::shared_ptr<jsi::Runtime> _runtime;
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
#else
|
|
46
46
|
_runtime = jsc::makeJSCRuntime();
|
|
47
47
|
#endif
|
|
48
|
-
_jsCallInvoker = std::make_shared<expo::
|
|
48
|
+
_jsCallInvoker = std::make_shared<expo::TestingJSCallInvoker>(_runtime);
|
|
49
49
|
}
|
|
50
50
|
return self;
|
|
51
51
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <Foundation/Foundation.h>
|
|
4
|
+
#import <ExpoModulesCore/EXJavaScriptRuntime.h>
|
|
5
|
+
|
|
6
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
7
|
+
|
|
8
|
+
typedef EXJavaScriptObject * _Nonnull (^EXJavaScriptObjectBindingGetter)(void);
|
|
9
|
+
|
|
10
|
+
NS_SWIFT_NAME(JavaScriptSharedObjectBinding)
|
|
11
|
+
@interface EXJavaScriptSharedObjectBinding : NSObject
|
|
12
|
+
|
|
13
|
+
@property (nonatomic, copy) EXJavaScriptObjectBindingGetter getter;
|
|
14
|
+
|
|
15
|
+
- (instancetype)initWithGetter:(EXJavaScriptObjectBindingGetter)getter
|
|
16
|
+
NS_DESIGNATED_INITIALIZER
|
|
17
|
+
NS_SWIFT_NAME(init(getter:));
|
|
18
|
+
|
|
19
|
+
- (instancetype)init NS_UNAVAILABLE;
|
|
20
|
+
|
|
21
|
+
- (EXJavaScriptObject *)get;
|
|
22
|
+
|
|
23
|
+
@end
|
|
24
|
+
|
|
25
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright 2025-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoModulesCore/EXJSIConversions.h>
|
|
4
|
+
#import <ExpoModulesCore/EXJavaScriptSharedObjectBinding.h>
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
A wrapper around a SharedObject getter – The getter is a Swift lambda that creates the JS object and registers the pair in registry.
|
|
8
|
+
Needed to make sure the registration happens on the correct thread when called from inside EXJSIConversions.
|
|
9
|
+
*/
|
|
10
|
+
@implementation EXJavaScriptSharedObjectBinding
|
|
11
|
+
|
|
12
|
+
- (nonnull instancetype)initWithGetter:(EXJavaScriptObjectBindingGetter)getter
|
|
13
|
+
{
|
|
14
|
+
self.getter = getter;
|
|
15
|
+
return self;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
- (EXJavaScriptObject *)get
|
|
19
|
+
{
|
|
20
|
+
auto obj = self.getter();
|
|
21
|
+
return obj;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#ifdef __cplusplus
|
|
6
|
+
|
|
7
|
+
#include <functional>
|
|
8
|
+
|
|
9
|
+
class MainThreadInvoker {
|
|
10
|
+
public:
|
|
11
|
+
static void invokeOnMainThread(const std::function<void()> task);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
#endif // __cplusplus
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2023-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#ifdef __cplusplus
|
|
4
|
+
|
|
5
|
+
#import <ExpoModulesCore/MainThreadInvoker.h>
|
|
6
|
+
#import <Foundation/Foundation.h>
|
|
7
|
+
|
|
8
|
+
void MainThreadInvoker::invokeOnMainThread(const std::function<void()> task) {
|
|
9
|
+
dispatch_block_t block = [task]() {
|
|
10
|
+
task();
|
|
11
|
+
};
|
|
12
|
+
if ([NSThread isMainThread]) {
|
|
13
|
+
block();
|
|
14
|
+
} else {
|
|
15
|
+
dispatch_async(dispatch_get_main_queue(), block);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#endif // __cplusplus
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Copyright 2015-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#pragma once
|
|
4
|
+
|
|
5
|
+
#ifdef __cplusplus
|
|
6
|
+
|
|
7
|
+
#include <ReactCommon/CallInvoker.h>
|
|
8
|
+
#include <ExpoModulesCore/MainThreadInvoker.h>
|
|
9
|
+
|
|
10
|
+
#include <jsi/jsi.h>
|
|
11
|
+
|
|
12
|
+
namespace jsi = facebook::jsi;
|
|
13
|
+
namespace react = facebook::react;
|
|
14
|
+
|
|
15
|
+
namespace expo {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Dummy CallInvoker.
|
|
19
|
+
* Async functions are invoked on the main thread on iOS.
|
|
20
|
+
* Used in the test environment to check the async flow.
|
|
21
|
+
*/
|
|
22
|
+
class TestingJSCallInvoker : public react::CallInvoker {
|
|
23
|
+
public:
|
|
24
|
+
explicit TestingJSCallInvoker(const std::shared_ptr<jsi::Runtime>& runtime) : runtime(runtime) {}
|
|
25
|
+
|
|
26
|
+
void invokeAsync(react::CallFunc &&func) noexcept override {
|
|
27
|
+
auto weakRuntime = runtime;
|
|
28
|
+
std::function<void()> mainThreadFunc = [weakRuntime, func]() {
|
|
29
|
+
auto strongRuntime = weakRuntime.lock();
|
|
30
|
+
func(*strongRuntime);
|
|
31
|
+
};
|
|
32
|
+
MainThreadInvoker::invokeOnMainThread(mainThreadFunc);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void invokeSync(react::CallFunc &&func) override {
|
|
36
|
+
func(*runtime.lock());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
~TestingJSCallInvoker() override = default;
|
|
40
|
+
|
|
41
|
+
std::weak_ptr<jsi::Runtime> runtime;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
} // namespace expo
|
|
45
|
+
|
|
46
|
+
#endif // __cplusplus
|