expo-modules-core 0.8.0 → 0.9.2
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 +22 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +11 -0
- package/android/src/main/java/expo/modules/kotlin/functions/AsyncFunctionBuilder.kt +127 -18
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +210 -26
- package/android/src/main/java/expo/modules/kotlin/views/ViewGroupDefinitionBuilder.kt +55 -5
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +43 -5
- package/ios/NativeModulesProxy/EXNativeModulesProxy.mm +3 -0
- package/ios/Swift/AppContext.swift +1 -8
- package/ios/Swift/Arguments/AnyArgumentType.swift +1 -1
- package/ios/Swift/Functions/AnyFunction.swift +5 -0
- package/ios/Swift/Functions/AsyncFunctionComponent.swift +182 -0
- package/ios/Swift/Functions/ConcreteFunction.swift +34 -67
- package/ios/Swift/Functions/SyncFunctionComponent.swift +181 -0
- package/ios/Swift/JavaScriptUtils.swift +51 -6
- package/ios/Swift/ModuleHolder.swift +11 -10
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +66 -44
- package/ios/Swift/Objects/ObjectDefinitionComponents.swift +45 -172
- package/ios/Swift/Views/ViewManagerDefinitionComponents.swift +23 -0
- package/ios/Tests/ConstantsSpec.swift +4 -4
- package/ios/Tests/ExpoModulesSpec.swift +3 -4
- package/ios/Tests/FunctionSpec.swift +11 -12
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +2 -2
- package/ios/Tests/ModuleEventListenersSpec.swift +13 -13
- package/package.json +2 -2
- package/ios/Swift/Functions/AsyncFunction.swift +0 -17
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
@file:OptIn(ExperimentalStdlibApi::class)
|
|
2
|
+
@file:Suppress("FunctionName")
|
|
2
3
|
|
|
3
4
|
package expo.modules.kotlin.views
|
|
4
5
|
|
|
@@ -12,12 +13,16 @@ import kotlin.reflect.typeOf
|
|
|
12
13
|
class ViewManagerDefinitionBuilder {
|
|
13
14
|
@PublishedApi
|
|
14
15
|
internal var viewFactory: ((Context) -> View)? = null
|
|
16
|
+
|
|
15
17
|
@PublishedApi
|
|
16
18
|
internal var viewType: Class<out View>? = null
|
|
19
|
+
|
|
17
20
|
@PublishedApi
|
|
18
21
|
internal var props = mutableMapOf<String, AnyViewProp>()
|
|
22
|
+
|
|
19
23
|
@PublishedApi
|
|
20
24
|
internal var onViewDestroys: ((View) -> Unit)? = null
|
|
25
|
+
|
|
21
26
|
@PublishedApi
|
|
22
27
|
internal var viewGroupDefinition: ViewGroupDefinition? = null
|
|
23
28
|
private var callbacksDefinition: CallbacksDefinition? = null
|
|
@@ -32,25 +37,46 @@ class ViewManagerDefinitionBuilder {
|
|
|
32
37
|
viewGroupDefinition
|
|
33
38
|
)
|
|
34
39
|
|
|
40
|
+
@Deprecated(
|
|
41
|
+
message = "The 'view' component was renamed to 'View'.",
|
|
42
|
+
replaceWith = ReplaceWith("View(body)")
|
|
43
|
+
)
|
|
44
|
+
inline fun <reified ViewType : View> view(noinline body: (Context) -> ViewType) = View(body)
|
|
45
|
+
|
|
35
46
|
/**
|
|
36
47
|
* Defines the factory creating a native view when the module is used as a view.
|
|
37
48
|
*/
|
|
38
|
-
inline fun <reified ViewType : View>
|
|
49
|
+
inline fun <reified ViewType : View> View(noinline body: (Context) -> ViewType) {
|
|
39
50
|
viewType = ViewType::class.java
|
|
40
51
|
viewFactory = body
|
|
41
52
|
}
|
|
42
53
|
|
|
54
|
+
@Deprecated(
|
|
55
|
+
message = "The 'onViewDestroys' component was renamed to 'OnViewDestroys'.",
|
|
56
|
+
replaceWith = ReplaceWith("OnViewDestroys(body)")
|
|
57
|
+
)
|
|
58
|
+
inline fun <reified ViewType : View> onViewDestroys(noinline body: (view: ViewType) -> Unit) = OnViewDestroys(body)
|
|
59
|
+
|
|
43
60
|
/**
|
|
44
61
|
* Creates view's lifecycle listener that is called right after the view isn't longer used by React Native.
|
|
45
62
|
*/
|
|
46
|
-
inline fun <reified ViewType : View>
|
|
63
|
+
inline fun <reified ViewType : View> OnViewDestroys(noinline body: (view: ViewType) -> Unit) {
|
|
47
64
|
onViewDestroys = { body(it as ViewType) }
|
|
48
65
|
}
|
|
49
66
|
|
|
67
|
+
@Deprecated(
|
|
68
|
+
message = "The 'prop' component was renamed to 'Prop'.",
|
|
69
|
+
replaceWith = ReplaceWith("Prop(body)")
|
|
70
|
+
)
|
|
71
|
+
inline fun <reified ViewType : View, reified PropType> prop(
|
|
72
|
+
name: String,
|
|
73
|
+
noinline body: (view: ViewType, prop: PropType) -> Unit
|
|
74
|
+
) = Prop(name, body)
|
|
75
|
+
|
|
50
76
|
/**
|
|
51
77
|
* Creates a view prop that defines its name and setter.
|
|
52
78
|
*/
|
|
53
|
-
inline fun <reified ViewType : View, reified PropType>
|
|
79
|
+
inline fun <reified ViewType : View, reified PropType> Prop(
|
|
54
80
|
name: String,
|
|
55
81
|
noinline body: (view: ViewType, prop: PropType) -> Unit
|
|
56
82
|
) {
|
|
@@ -61,17 +87,29 @@ class ViewManagerDefinitionBuilder {
|
|
|
61
87
|
)
|
|
62
88
|
}
|
|
63
89
|
|
|
90
|
+
@Deprecated(
|
|
91
|
+
message = "The 'events' component was renamed to 'Events'.",
|
|
92
|
+
replaceWith = ReplaceWith("Events(callbacks)")
|
|
93
|
+
)
|
|
94
|
+
fun events(vararg callbacks: String) = Events(*callbacks)
|
|
95
|
+
|
|
64
96
|
/**
|
|
65
97
|
* Defines prop names that should be treated as callbacks.
|
|
66
98
|
*/
|
|
67
|
-
fun
|
|
99
|
+
fun Events(vararg callbacks: String) {
|
|
68
100
|
callbacksDefinition = CallbacksDefinition(callbacks)
|
|
69
101
|
}
|
|
70
102
|
|
|
103
|
+
@Deprecated(
|
|
104
|
+
message = "The 'groupView' component was renamed to 'GroupView'.",
|
|
105
|
+
replaceWith = ReplaceWith("GroupView(callbacks)")
|
|
106
|
+
)
|
|
107
|
+
inline fun groupView(body: ViewGroupDefinitionBuilder.() -> Unit) = GroupView(body)
|
|
108
|
+
|
|
71
109
|
/**
|
|
72
110
|
* Creates the group view definition that scopes group view-related definitions.
|
|
73
111
|
*/
|
|
74
|
-
inline fun
|
|
112
|
+
inline fun GroupView(body: ViewGroupDefinitionBuilder.() -> Unit) {
|
|
75
113
|
require(viewGroupDefinition == null) { "The viewManager definition may have exported only one groupView definition." }
|
|
76
114
|
|
|
77
115
|
val groupViewDefinitionBuilder = ViewGroupDefinitionBuilder()
|
|
@@ -278,6 +278,9 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
278
278
|
// their base view managers that provides common props such as `proxiedProperties`.
|
|
279
279
|
// Otherwise, React Native may treat these props as invalid in subclassing views.
|
|
280
280
|
[additionalModuleClasses addObject:[EXViewManagerAdapter class]];
|
|
281
|
+
// Also, we have to register component data for the View Adapter.
|
|
282
|
+
// Otherwise, it won't be recognized by the UIManager.
|
|
283
|
+
[self registerLegacyComponentData:[EXViewManagerAdapter class] inBridge:bridge];
|
|
281
284
|
|
|
282
285
|
// Some modules might need access to the bridge.
|
|
283
286
|
for (id module in [_exModuleRegistry getAllInternalModules]) {
|
|
@@ -18,7 +18,7 @@ public final class AppContext {
|
|
|
18
18
|
/**
|
|
19
19
|
The legacy module registry with modules written in the old-fashioned way.
|
|
20
20
|
*/
|
|
21
|
-
public private(set) var legacyModuleRegistry: EXModuleRegistry?
|
|
21
|
+
public private(set) weak var legacyModuleRegistry: EXModuleRegistry?
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
React bridge of the context's app.
|
|
@@ -104,13 +104,6 @@ public final class AppContext {
|
|
|
104
104
|
return legacyModule(implementing: EXEventEmitterService.self)
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
/**
|
|
108
|
-
Provides access to the logger from legacy module registry.
|
|
109
|
-
*/
|
|
110
|
-
public var logger: EXLogManager? {
|
|
111
|
-
return legacyModuleRegistry?.getSingletonModule(forName: EXLogManager.name()) as? EXLogManager
|
|
112
|
-
}
|
|
113
|
-
|
|
114
107
|
/**
|
|
115
108
|
Starts listening to `UIApplication` notifications.
|
|
116
109
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
A protocol whose intention is to wrap function's argument type
|
|
5
5
|
to keep its real signature and not type-erase it by the compiler.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
public protocol AnyArgumentType: CustomStringConvertible {
|
|
8
8
|
/**
|
|
9
9
|
Casts given any value to the wrapped type and returns as `Any`.
|
|
10
10
|
NOTE: It may not be just simple type-casting (e.g. when the wrapped type conforms to `ConvertibleArgument`).
|
|
@@ -14,6 +14,11 @@ public protocol AnyFunction: AnyDefinition {
|
|
|
14
14
|
*/
|
|
15
15
|
var takesPromise: Bool { get }
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
An array of argument types that the function takes. If the last type is `Promise`, it's not included.
|
|
19
|
+
*/
|
|
20
|
+
var argumentTypes: [AnyArgumentType] { get }
|
|
21
|
+
|
|
17
22
|
/**
|
|
18
23
|
A number of arguments the function takes. If the last argument is of type `Promise`, it is not counted.
|
|
19
24
|
*/
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Represents a function that can only be called asynchronously, thus its JavaScript equivalent returns a Promise.
|
|
5
|
+
|
|
6
|
+
- ToDo: Move some asynchronous logic from `ConcreteFunction` (like `call(args:promise:)`) to this class and drop the `isAsync` property.
|
|
7
|
+
*/
|
|
8
|
+
internal final class AsyncFunctionComponent<Args, ReturnType>: ConcreteFunction<Args, ReturnType> {
|
|
9
|
+
override init(
|
|
10
|
+
_ name: String,
|
|
11
|
+
argTypes: [AnyArgumentType],
|
|
12
|
+
_ closure: @escaping ConcreteFunction<Args, ReturnType>.ClosureType
|
|
13
|
+
) {
|
|
14
|
+
super.init(name, argTypes: argTypes, closure)
|
|
15
|
+
self.isAsync = true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
Asynchronous function without arguments.
|
|
21
|
+
*/
|
|
22
|
+
public func AsyncFunction<R>(
|
|
23
|
+
_ name: String,
|
|
24
|
+
_ closure: @escaping () throws -> R
|
|
25
|
+
) -> AnyFunction {
|
|
26
|
+
return AsyncFunctionComponent(
|
|
27
|
+
name,
|
|
28
|
+
argTypes: [],
|
|
29
|
+
closure
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
Asynchronous function with one argument.
|
|
35
|
+
*/
|
|
36
|
+
public func AsyncFunction<R, A0: AnyArgument>(
|
|
37
|
+
_ name: String,
|
|
38
|
+
_ closure: @escaping (A0) throws -> R
|
|
39
|
+
) -> AnyFunction {
|
|
40
|
+
return AsyncFunctionComponent(
|
|
41
|
+
name,
|
|
42
|
+
argTypes: [ArgumentType(A0.self)],
|
|
43
|
+
closure
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
Asynchronous function with two arguments.
|
|
49
|
+
*/
|
|
50
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument>(
|
|
51
|
+
_ name: String,
|
|
52
|
+
_ closure: @escaping (A0, A1) throws -> R
|
|
53
|
+
) -> AnyFunction {
|
|
54
|
+
return AsyncFunctionComponent(
|
|
55
|
+
name,
|
|
56
|
+
argTypes: [ArgumentType(A0.self), ArgumentType(A1.self)],
|
|
57
|
+
closure
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
Asynchronous function with three arguments.
|
|
63
|
+
*/
|
|
64
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>(
|
|
65
|
+
_ name: String,
|
|
66
|
+
_ closure: @escaping (A0, A1, A2) throws -> R
|
|
67
|
+
) -> AnyFunction {
|
|
68
|
+
return AsyncFunctionComponent(
|
|
69
|
+
name,
|
|
70
|
+
argTypes: [
|
|
71
|
+
ArgumentType(A0.self),
|
|
72
|
+
ArgumentType(A1.self),
|
|
73
|
+
ArgumentType(A2.self)
|
|
74
|
+
],
|
|
75
|
+
closure
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
Asynchronous function with four arguments.
|
|
81
|
+
*/
|
|
82
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>(
|
|
83
|
+
_ name: String,
|
|
84
|
+
_ closure: @escaping (A0, A1, A2, A3) throws -> R
|
|
85
|
+
) -> AnyFunction {
|
|
86
|
+
return AsyncFunctionComponent(
|
|
87
|
+
name,
|
|
88
|
+
argTypes: [
|
|
89
|
+
ArgumentType(A0.self),
|
|
90
|
+
ArgumentType(A1.self),
|
|
91
|
+
ArgumentType(A2.self),
|
|
92
|
+
ArgumentType(A3.self)
|
|
93
|
+
],
|
|
94
|
+
closure
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
Asynchronous function with five arguments.
|
|
100
|
+
*/
|
|
101
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>(
|
|
102
|
+
_ name: String,
|
|
103
|
+
_ closure: @escaping (A0, A1, A2, A3, A4) throws -> R
|
|
104
|
+
) -> AnyFunction {
|
|
105
|
+
return AsyncFunctionComponent(
|
|
106
|
+
name,
|
|
107
|
+
argTypes: [
|
|
108
|
+
ArgumentType(A0.self),
|
|
109
|
+
ArgumentType(A1.self),
|
|
110
|
+
ArgumentType(A2.self),
|
|
111
|
+
ArgumentType(A3.self),
|
|
112
|
+
ArgumentType(A4.self)
|
|
113
|
+
],
|
|
114
|
+
closure
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
Asynchronous function with six arguments.
|
|
120
|
+
*/
|
|
121
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>(
|
|
122
|
+
_ name: String,
|
|
123
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5) throws -> R
|
|
124
|
+
) -> AnyFunction {
|
|
125
|
+
return AsyncFunctionComponent(
|
|
126
|
+
name,
|
|
127
|
+
argTypes: [
|
|
128
|
+
ArgumentType(A0.self),
|
|
129
|
+
ArgumentType(A1.self),
|
|
130
|
+
ArgumentType(A2.self),
|
|
131
|
+
ArgumentType(A3.self),
|
|
132
|
+
ArgumentType(A4.self),
|
|
133
|
+
ArgumentType(A5.self)
|
|
134
|
+
],
|
|
135
|
+
closure
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
Asynchronous function with seven arguments.
|
|
141
|
+
*/
|
|
142
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument>(
|
|
143
|
+
_ name: String,
|
|
144
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6) throws -> R
|
|
145
|
+
) -> AnyFunction {
|
|
146
|
+
return AsyncFunctionComponent(
|
|
147
|
+
name,
|
|
148
|
+
argTypes: [
|
|
149
|
+
ArgumentType(A0.self),
|
|
150
|
+
ArgumentType(A1.self),
|
|
151
|
+
ArgumentType(A2.self),
|
|
152
|
+
ArgumentType(A3.self),
|
|
153
|
+
ArgumentType(A4.self),
|
|
154
|
+
ArgumentType(A5.self),
|
|
155
|
+
ArgumentType(A6.self)
|
|
156
|
+
],
|
|
157
|
+
closure
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
Asynchronous function with eight arguments.
|
|
163
|
+
*/
|
|
164
|
+
public func AsyncFunction<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument, A7: AnyArgument>(
|
|
165
|
+
_ name: String,
|
|
166
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6, A7) throws -> R
|
|
167
|
+
) -> AnyFunction {
|
|
168
|
+
return AsyncFunctionComponent(
|
|
169
|
+
name,
|
|
170
|
+
argTypes: [
|
|
171
|
+
ArgumentType(A0.self),
|
|
172
|
+
ArgumentType(A1.self),
|
|
173
|
+
ArgumentType(A2.self),
|
|
174
|
+
ArgumentType(A3.self),
|
|
175
|
+
ArgumentType(A4.self),
|
|
176
|
+
ArgumentType(A5.self),
|
|
177
|
+
ArgumentType(A6.self),
|
|
178
|
+
ArgumentType(A7.self)
|
|
179
|
+
],
|
|
180
|
+
closure
|
|
181
|
+
)
|
|
182
|
+
}
|
|
@@ -5,12 +5,10 @@ public class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
5
5
|
|
|
6
6
|
public let name: String
|
|
7
7
|
|
|
8
|
-
public var takesPromise: Bool
|
|
9
|
-
return argTypes.last is PromiseArgumentType
|
|
10
|
-
}
|
|
8
|
+
public var takesPromise: Bool
|
|
11
9
|
|
|
12
10
|
public var argumentsCount: Int {
|
|
13
|
-
return
|
|
11
|
+
return argumentTypes.count
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
public var queue: DispatchQueue?
|
|
@@ -19,7 +17,7 @@ public class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
19
17
|
|
|
20
18
|
let closure: ClosureType
|
|
21
19
|
|
|
22
|
-
let
|
|
20
|
+
public let argumentTypes: [AnyArgumentType]
|
|
23
21
|
|
|
24
22
|
init(
|
|
25
23
|
_ name: String,
|
|
@@ -27,28 +25,33 @@ public class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
27
25
|
_ closure: @escaping ClosureType
|
|
28
26
|
) {
|
|
29
27
|
self.name = name
|
|
30
|
-
self.
|
|
28
|
+
self.takesPromise = argTypes.last is PromiseArgumentType
|
|
31
29
|
self.closure = closure
|
|
32
30
|
|
|
31
|
+
// Drop the last argument type if it's the `Promise`.
|
|
32
|
+
self.argumentTypes = takesPromise ? argTypes.dropLast(1) : argTypes
|
|
33
|
+
|
|
33
34
|
// This is temporary solution to keep backwards compatibility for existing functions — they all end with "Async".
|
|
34
35
|
// `function` component that we've used so far was async by default, but we decided to replace it with `asyncFunction`
|
|
35
36
|
// and make `function`s synchronous. Introduced in SDK45, can be removed in SDK46 after migrating all modules.
|
|
36
37
|
self.isAsync = name.hasSuffix("Async")
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
Calls the function with given arguments.
|
|
42
|
+
- Parameters:
|
|
43
|
+
- args: An array of arguments to pass to the function. The arguments must be of the same type as in the underlying ``closure``.
|
|
44
|
+
- promise: A promise to resolve or reject by the async ``closure`` when it finishes execution.
|
|
45
|
+
- ToDo: Make it internal.
|
|
46
|
+
*/
|
|
39
47
|
public func call(args: [Any], promise: Promise) {
|
|
40
|
-
|
|
48
|
+
// Add promise to the array of arguments if necessary.
|
|
49
|
+
let arguments = takesPromise ? args + [promise] : args
|
|
41
50
|
let returnedValue: ReturnType?
|
|
42
51
|
|
|
43
52
|
do {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if takesPromise {
|
|
47
|
-
finalArgs.append(promise)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let tuple = try Conversions.toTuple(finalArgs) as! Args
|
|
51
|
-
returnedValue = try closure(tuple)
|
|
53
|
+
let argumentsTuple = try Conversions.toTuple(arguments) as! Args
|
|
54
|
+
returnedValue = try closure(argumentsTuple)
|
|
52
55
|
} catch let error as CodedError {
|
|
53
56
|
promise.reject(FunctionCallException(name).causedBy(error))
|
|
54
57
|
return
|
|
@@ -61,28 +64,24 @@ public class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
61
64
|
}
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
/**
|
|
68
|
+
Calls the function synchronously with given arguments.
|
|
69
|
+
- Parameters:
|
|
70
|
+
- args: An array of arguments to pass to the function. The arguments must be of the same type as in the underlying ``closure``.
|
|
71
|
+
- Returns: A value returned by the called function when succeeded or an error when it failed.
|
|
72
|
+
- ToDo: Make it internal.
|
|
73
|
+
*/
|
|
64
74
|
public func callSync(args: [Any]) -> Any {
|
|
65
75
|
if takesPromise {
|
|
66
|
-
|
|
67
|
-
let
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
call(args: args, promise: promise)
|
|
76
|
-
semaphore.wait()
|
|
77
|
-
return result as Any
|
|
78
|
-
} else {
|
|
79
|
-
do {
|
|
80
|
-
let finalArgs = try castArguments(args)
|
|
81
|
-
let tuple = try Conversions.toTuple(finalArgs) as! Args
|
|
82
|
-
return try closure(tuple)
|
|
83
|
-
} catch let error {
|
|
84
|
-
return error
|
|
85
|
-
}
|
|
76
|
+
// Using `Promise` in the synchronous function is prohibited. Probably should throw an exception here,
|
|
77
|
+
// but for now let's return nil until we split async and sync functions.
|
|
78
|
+
return Optional<Any>.none as Any
|
|
79
|
+
}
|
|
80
|
+
do {
|
|
81
|
+
let argumentsTuple = try Conversions.toTuple(args) as! Args
|
|
82
|
+
return try closure(argumentsTuple)
|
|
83
|
+
} catch let error {
|
|
84
|
+
return error
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
|
|
@@ -95,38 +94,6 @@ public class ConcreteFunction<Args, ReturnType>: AnyFunction {
|
|
|
95
94
|
self.isAsync = false
|
|
96
95
|
return self
|
|
97
96
|
}
|
|
98
|
-
|
|
99
|
-
private func argumentType(atIndex index: Int) -> AnyArgumentType? {
|
|
100
|
-
return (0..<argTypes.count).contains(index) ? argTypes[index] : nil
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private func castArguments(_ args: [Any]) throws -> [Any] {
|
|
104
|
-
if args.count != argumentsCount {
|
|
105
|
-
throw InvalidArgsNumberException((received: args.count, expected: argumentsCount))
|
|
106
|
-
}
|
|
107
|
-
return try args.enumerated().map { index, arg in
|
|
108
|
-
let expectedType = argumentType(atIndex: index)
|
|
109
|
-
|
|
110
|
-
do {
|
|
111
|
-
// It's safe to unwrap since the arguments count matches.
|
|
112
|
-
return try expectedType!.cast(arg)
|
|
113
|
-
} catch {
|
|
114
|
-
throw ArgumentCastException((index: index, type: expectedType!)).causedBy(error)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
internal class InvalidArgsNumberException: GenericException<(received: Int, expected: Int)> {
|
|
121
|
-
override var reason: String {
|
|
122
|
-
"Received \(param.received) arguments, but \(param.expected) was expected"
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
internal class ArgumentCastException: GenericException<(index: Int, type: AnyArgumentType)> {
|
|
127
|
-
override var reason: String {
|
|
128
|
-
"Argument at index '\(param.index)' couldn't be cast to type \(param.type.description)"
|
|
129
|
-
}
|
|
130
97
|
}
|
|
131
98
|
|
|
132
99
|
internal class FunctionCallException: GenericException<String> {
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Copyright 2022-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Represents a function that can only be called synchronously.
|
|
5
|
+
- ToDo: Move some synchronous logic from `ConcreteFunction` (like `call(args:)`) to this class and drop the `isAsync` property.
|
|
6
|
+
*/
|
|
7
|
+
internal final class SyncFunctionComponent<Args, ReturnType>: ConcreteFunction<Args, ReturnType> {
|
|
8
|
+
override init(
|
|
9
|
+
_ name: String,
|
|
10
|
+
argTypes: [AnyArgumentType],
|
|
11
|
+
_ closure: @escaping ConcreteFunction<Args, ReturnType>.ClosureType
|
|
12
|
+
) {
|
|
13
|
+
super.init(name, argTypes: argTypes, closure)
|
|
14
|
+
self.isAsync = false
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
Synchronous function without arguments.
|
|
20
|
+
*/
|
|
21
|
+
public func Function<R>(
|
|
22
|
+
_ name: String,
|
|
23
|
+
_ closure: @escaping () throws -> R
|
|
24
|
+
) -> AnyFunction {
|
|
25
|
+
return SyncFunctionComponent(
|
|
26
|
+
name,
|
|
27
|
+
argTypes: [],
|
|
28
|
+
closure
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
Synchronous function with one argument.
|
|
34
|
+
*/
|
|
35
|
+
public func Function<R, A0: AnyArgument>(
|
|
36
|
+
_ name: String,
|
|
37
|
+
_ closure: @escaping (A0) throws -> R
|
|
38
|
+
) -> AnyFunction {
|
|
39
|
+
return SyncFunctionComponent(
|
|
40
|
+
name,
|
|
41
|
+
argTypes: [ArgumentType(A0.self)],
|
|
42
|
+
closure
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
Synchronous function with two arguments.
|
|
48
|
+
*/
|
|
49
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument>(
|
|
50
|
+
_ name: String,
|
|
51
|
+
_ closure: @escaping (A0, A1) throws -> R
|
|
52
|
+
) -> AnyFunction {
|
|
53
|
+
return SyncFunctionComponent(
|
|
54
|
+
name,
|
|
55
|
+
argTypes: [ArgumentType(A0.self), ArgumentType(A1.self)],
|
|
56
|
+
closure
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
Synchronous function with three arguments.
|
|
62
|
+
*/
|
|
63
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>(
|
|
64
|
+
_ name: String,
|
|
65
|
+
_ closure: @escaping (A0, A1, A2) throws -> R
|
|
66
|
+
) -> AnyFunction {
|
|
67
|
+
return SyncFunctionComponent(
|
|
68
|
+
name,
|
|
69
|
+
argTypes: [
|
|
70
|
+
ArgumentType(A0.self),
|
|
71
|
+
ArgumentType(A1.self),
|
|
72
|
+
ArgumentType(A2.self)
|
|
73
|
+
],
|
|
74
|
+
closure
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
Synchronous function with four arguments.
|
|
80
|
+
*/
|
|
81
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>(
|
|
82
|
+
_ name: String,
|
|
83
|
+
_ closure: @escaping (A0, A1, A2, A3) throws -> R
|
|
84
|
+
) -> AnyFunction {
|
|
85
|
+
return SyncFunctionComponent(
|
|
86
|
+
name,
|
|
87
|
+
argTypes: [
|
|
88
|
+
ArgumentType(A0.self),
|
|
89
|
+
ArgumentType(A1.self),
|
|
90
|
+
ArgumentType(A2.self),
|
|
91
|
+
ArgumentType(A3.self)
|
|
92
|
+
],
|
|
93
|
+
closure
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
Synchronous function with five arguments.
|
|
99
|
+
*/
|
|
100
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>(
|
|
101
|
+
_ name: String,
|
|
102
|
+
_ closure: @escaping (A0, A1, A2, A3, A4) throws -> R
|
|
103
|
+
) -> AnyFunction {
|
|
104
|
+
return SyncFunctionComponent(
|
|
105
|
+
name,
|
|
106
|
+
argTypes: [
|
|
107
|
+
ArgumentType(A0.self),
|
|
108
|
+
ArgumentType(A1.self),
|
|
109
|
+
ArgumentType(A2.self),
|
|
110
|
+
ArgumentType(A3.self),
|
|
111
|
+
ArgumentType(A4.self)
|
|
112
|
+
],
|
|
113
|
+
closure
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
Synchronous function with six arguments.
|
|
119
|
+
*/
|
|
120
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>(
|
|
121
|
+
_ name: String,
|
|
122
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5) throws -> R
|
|
123
|
+
) -> AnyFunction {
|
|
124
|
+
return SyncFunctionComponent(
|
|
125
|
+
name,
|
|
126
|
+
argTypes: [
|
|
127
|
+
ArgumentType(A0.self),
|
|
128
|
+
ArgumentType(A1.self),
|
|
129
|
+
ArgumentType(A2.self),
|
|
130
|
+
ArgumentType(A3.self),
|
|
131
|
+
ArgumentType(A4.self),
|
|
132
|
+
ArgumentType(A5.self)
|
|
133
|
+
],
|
|
134
|
+
closure
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
Synchronous function with seven arguments.
|
|
140
|
+
*/
|
|
141
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument>(
|
|
142
|
+
_ name: String,
|
|
143
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6) throws -> R
|
|
144
|
+
) -> AnyFunction {
|
|
145
|
+
return SyncFunctionComponent(
|
|
146
|
+
name,
|
|
147
|
+
argTypes: [
|
|
148
|
+
ArgumentType(A0.self),
|
|
149
|
+
ArgumentType(A1.self),
|
|
150
|
+
ArgumentType(A2.self),
|
|
151
|
+
ArgumentType(A3.self),
|
|
152
|
+
ArgumentType(A4.self),
|
|
153
|
+
ArgumentType(A5.self),
|
|
154
|
+
ArgumentType(A6.self)
|
|
155
|
+
],
|
|
156
|
+
closure
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
Synchronous function with eight arguments.
|
|
162
|
+
*/
|
|
163
|
+
public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument, A7: AnyArgument>(
|
|
164
|
+
_ name: String,
|
|
165
|
+
_ closure: @escaping (A0, A1, A2, A3, A4, A5, A6, A7) throws -> R
|
|
166
|
+
) -> AnyFunction {
|
|
167
|
+
return SyncFunctionComponent(
|
|
168
|
+
name,
|
|
169
|
+
argTypes: [
|
|
170
|
+
ArgumentType(A0.self),
|
|
171
|
+
ArgumentType(A1.self),
|
|
172
|
+
ArgumentType(A2.self),
|
|
173
|
+
ArgumentType(A3.self),
|
|
174
|
+
ArgumentType(A4.self),
|
|
175
|
+
ArgumentType(A5.self),
|
|
176
|
+
ArgumentType(A6.self),
|
|
177
|
+
ArgumentType(A7.self)
|
|
178
|
+
],
|
|
179
|
+
closure
|
|
180
|
+
)
|
|
181
|
+
}
|