expo-modules-core 0.4.8 → 0.5.0
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 +30 -2
- package/android/src/main/java/expo/modules/adapters/react/ModuleRegistryAdapter.java +27 -5
- package/android/src/main/java/expo/modules/adapters/react/NativeModulesProxy.java +49 -5
- package/android/src/main/java/expo/modules/core/BasePackage.java +6 -0
- package/android/src/main/java/expo/modules/core/ModulePriorities.kt +25 -0
- package/android/src/main/java/expo/modules/core/interfaces/ActivityEventListener.java +3 -1
- package/android/src/main/java/expo/modules/core/interfaces/Package.java +4 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactActivityHandler.kt +18 -0
- package/android/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.kt +14 -0
- package/android/src/main/java/expo/modules/core/utilities/KotlinUtilities.kt +23 -0
- package/android/src/main/java/expo/modules/kotlin/AppContext.kt +166 -0
- package/android/src/main/java/expo/modules/kotlin/DynamicExtenstions.kt +9 -0
- package/android/src/main/java/expo/modules/kotlin/ExpoModulesHelper.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/KPromiseWrapper.kt +23 -0
- package/android/src/main/java/expo/modules/kotlin/KotlinInteropModuleRegistry.kt +98 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleHolder.kt +41 -0
- package/android/src/main/java/expo/modules/kotlin/ModuleRegistry.kt +56 -0
- package/android/src/main/java/expo/modules/kotlin/ModulesProvider.kt +7 -0
- package/android/src/main/java/expo/modules/kotlin/Promise.kt +13 -0
- package/android/src/main/java/expo/modules/kotlin/ReactLifecycleDelegate.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/ReadableArrayIterator.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/ReadableTypeExtensions.kt +18 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructor.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/ObjectConstructorFactory.kt +31 -0
- package/android/src/main/java/expo/modules/kotlin/allocators/UnsafeAllocator.kt +49 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventListener.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventName.kt +31 -0
- package/android/src/main/java/expo/modules/kotlin/events/EventsDefinition.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/events/KEventEmitterWrapper.kt +26 -0
- package/android/src/main/java/expo/modules/kotlin/events/OnActivityResultPayload.kt +8 -0
- package/android/src/main/java/expo/modules/kotlin/exception/CodedException.kt +70 -0
- package/android/src/main/java/expo/modules/kotlin/methods/AnyMethod.kt +50 -0
- package/android/src/main/java/expo/modules/kotlin/methods/Method.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/methods/PromiseMethod.kt +15 -0
- package/android/src/main/java/expo/modules/kotlin/modules/Module.kt +24 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionBuilder.kt +227 -0
- package/android/src/main/java/expo/modules/kotlin/modules/ModuleDefinitionData.kt +16 -0
- package/android/src/main/java/expo/modules/kotlin/records/Field.kt +5 -0
- package/android/src/main/java/expo/modules/kotlin/records/Record.kt +3 -0
- package/android/src/main/java/expo/modules/kotlin/records/RecordTypeConverter.kt +55 -0
- package/android/src/main/java/expo/modules/kotlin/types/AnyType.kt +14 -0
- package/android/src/main/java/expo/modules/kotlin/types/ArrayTypeConverter.kt +44 -0
- package/android/src/main/java/expo/modules/kotlin/types/BasicTypeConverters.kt +60 -0
- package/android/src/main/java/expo/modules/kotlin/types/EnumTypeConverter.kt +84 -0
- package/android/src/main/java/expo/modules/kotlin/types/ListTypeConverter.kt +25 -0
- package/android/src/main/java/expo/modules/kotlin/types/MapTypeConverter.kt +39 -0
- package/android/src/main/java/expo/modules/kotlin/types/PairTypeConverter.kt +28 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverter.kt +19 -0
- package/android/src/main/java/expo/modules/kotlin/types/TypeConverterProvider.kt +107 -0
- package/android/src/main/java/expo/modules/kotlin/views/AnyViewProp.kt +10 -0
- package/android/src/main/java/expo/modules/kotlin/views/ConcreteViewProp.kt +17 -0
- package/android/src/main/java/expo/modules/kotlin/views/GroupViewManagerWrapper.kt +22 -0
- package/android/src/main/java/expo/modules/kotlin/views/SimpleViewManagerWrapper.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinition.kt +36 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerDefinitionBuilder.kt +40 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewManagerWrapperDelegate.kt +21 -0
- package/android/src/main/java/expo/modules/kotlin/views/ViewWrapperDelegateHolder.kt +5 -0
- package/build/NativeModulesProxy.native.d.ts +4 -0
- package/build/NativeModulesProxy.native.js +14 -1
- package/build/NativeModulesProxy.native.js.map +1 -1
- package/build/NativeModulesProxy.types.d.ts +3 -0
- package/build/NativeModulesProxy.types.js.map +1 -1
- package/ios/AppDelegates/EXAppDelegateWrapper.h +16 -0
- package/ios/AppDelegates/EXAppDelegateWrapper.m +42 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.h +15 -0
- package/ios/AppDelegates/EXAppDelegatesLoader.m +29 -0
- package/ios/AppDelegates/EXLegacyAppDelegateWrapper.h +16 -0
- package/ios/{EXAppDelegateWrapper.m → AppDelegates/EXLegacyAppDelegateWrapper.m} +2 -2
- package/ios/AppDelegates/ExpoAppDelegate.swift +264 -0
- package/ios/AppDelegates/ExpoAppDelegateSubscriber.swift +24 -0
- package/ios/ExpoModulesCore.podspec +7 -2
- package/ios/JSI/ExpoModulesProxySpec.h +24 -0
- package/ios/JSI/ExpoModulesProxySpec.mm +135 -0
- package/ios/JSI/JSIConversions.h +42 -0
- package/ios/JSI/JSIConversions.mm +164 -0
- package/ios/JSI/JSIInstaller.h +19 -0
- package/ios/JSI/JSIInstaller.mm +22 -0
- package/ios/ModuleRegistryAdapter/EXModuleRegistryAdapter.m +1 -6
- package/ios/NativeModulesProxy/EXNativeModulesProxy.h +6 -0
- package/ios/NativeModulesProxy/{EXNativeModulesProxy.m → EXNativeModulesProxy.mm} +45 -12
- package/ios/Services/EXReactNativeEventEmitter.h +6 -0
- package/ios/Services/EXReactNativeEventEmitter.m +15 -0
- package/ios/Swift/AppContext.swift +14 -1
- package/ios/Swift/Arguments/AnyArgument.swift +14 -0
- package/ios/Swift/Arguments/AnyArgumentType.swift +13 -0
- package/ios/Swift/Arguments/ArgumentType.swift +24 -0
- package/ios/Swift/Arguments/ConvertibleArgument.swift +15 -0
- package/ios/Swift/Arguments/Convertibles.swift +93 -0
- package/ios/Swift/Arguments/Types/ArrayArgumentType.swift +42 -0
- package/ios/Swift/Arguments/Types/ConvertibleArgumentType.swift +16 -0
- package/ios/Swift/Arguments/Types/EnumArgumentType.swift +105 -0
- package/ios/Swift/Arguments/Types/OptionalArgumentType.swift +49 -0
- package/ios/Swift/Arguments/Types/PromiseArgumentType.swift +15 -0
- package/ios/Swift/Arguments/Types/RawArgumentType.swift +25 -0
- package/ios/Swift/Conversions.swift +199 -7
- package/ios/Swift/EventListener.swift +37 -5
- package/ios/Swift/Functions/AnyFunction.swift +42 -0
- package/ios/Swift/{Methods/ConcreteMethod.swift → Functions/ConcreteFunction.swift} +32 -34
- package/ios/Swift/ModuleHolder.swift +75 -20
- package/ios/Swift/ModuleRegistry.swift +19 -8
- package/ios/Swift/Modules/AnyModule.swift +8 -8
- package/ios/Swift/Modules/Module.swift +7 -0
- package/ios/Swift/Modules/ModuleDefinition.swift +52 -8
- package/ios/Swift/Modules/ModuleDefinitionBuilder.swift +1 -1
- package/ios/Swift/Modules/ModuleDefinitionComponents.swift +140 -52
- package/ios/Swift/ModulesProvider.swift +9 -0
- package/ios/Swift/Promise.swift +1 -1
- package/ios/Swift/Records/Field.swift +1 -1
- package/ios/Swift/Records/Record.swift +8 -1
- package/ios/Swift/SwiftInteropBridge.swift +45 -16
- package/ios/Swift/Views/AnyViewProp.swift +2 -2
- package/ios/Swift/Views/ConcreteViewProp.swift +37 -10
- package/ios/Swift/Views/ViewModuleWrapper.swift +9 -4
- package/ios/Swift.h +9 -0
- package/ios/Tests/ArgumentTypeSpec.swift +145 -0
- package/ios/Tests/ConvertiblesSpec.swift +231 -0
- package/ios/Tests/{MethodSpec.swift → FunctionSpec.swift} +69 -54
- package/ios/Tests/FunctionWithConvertiblesSpec.swift +66 -0
- package/ios/Tests/Mocks/ModuleMocks.swift +21 -7
- package/ios/Tests/ModuleEventListenersSpec.swift +17 -16
- package/ios/Tests/ModuleRegistrySpec.swift +4 -7
- package/package.json +3 -3
- package/src/NativeModulesProxy.native.ts +22 -2
- package/src/NativeModulesProxy.types.ts +8 -0
- package/ios/EXAppDelegateWrapper.h +0 -13
- package/ios/Swift/Methods/AnyArgumentType.swift +0 -48
- package/ios/Swift/Methods/AnyMethod.swift +0 -31
- package/ios/Swift/Methods/AnyMethodArgument.swift +0 -13
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2018-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#ifdef __cplusplus
|
|
4
|
+
|
|
5
|
+
#import <jsi/jsi.h>
|
|
6
|
+
#import <ReactCommon/RCTTurboModule.h>
|
|
7
|
+
|
|
8
|
+
#import <ExpoModulesCore/EXNativeModulesProxy.h>
|
|
9
|
+
|
|
10
|
+
using namespace facebook;
|
|
11
|
+
using namespace react;
|
|
12
|
+
|
|
13
|
+
namespace expo {
|
|
14
|
+
|
|
15
|
+
void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy);
|
|
16
|
+
|
|
17
|
+
} // namespace expo
|
|
18
|
+
|
|
19
|
+
#endif
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright 2018-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
#import <ExpoModulesCore/JSIInstaller.h>
|
|
4
|
+
#import <ExpoModulesCore/ExpoModulesProxySpec.h>
|
|
5
|
+
|
|
6
|
+
using namespace facebook;
|
|
7
|
+
using namespace react;
|
|
8
|
+
|
|
9
|
+
//using PromiseInvocationBlock = void (^)(RCTPromiseResolveBlock resolveWrapper, RCTPromiseRejectBlock rejectWrapper);
|
|
10
|
+
|
|
11
|
+
namespace expo {
|
|
12
|
+
|
|
13
|
+
void installRuntimeObjects(jsi::Runtime &runtime, std::shared_ptr<CallInvoker> callInvoker, EXNativeModulesProxy *nativeModulesProxy)
|
|
14
|
+
{
|
|
15
|
+
auto expoModulesProxyModule = std::make_shared<ExpoModulesProxySpec>(callInvoker, nativeModulesProxy);
|
|
16
|
+
|
|
17
|
+
runtime
|
|
18
|
+
.global()
|
|
19
|
+
.setProperty(runtime, "ExpoModulesProxy", jsi::Object::createFromHostObject(runtime, expoModulesProxyModule));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
} // namespace expo
|
|
@@ -7,12 +7,7 @@
|
|
|
7
7
|
#import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
|
|
8
8
|
#import <ExpoModulesCore/EXModuleRegistryHolderReactModule.h>
|
|
9
9
|
#import <ExpoModulesCore/EXReactNativeEventEmitter.h>
|
|
10
|
-
#
|
|
11
|
-
// For cocoapods framework, the generated swift header will be inside ExpoModulesCore module
|
|
12
|
-
#import <ExpoModulesCore/ExpoModulesCore-Swift.h>
|
|
13
|
-
#else
|
|
14
|
-
#import "ExpoModulesCore-Swift.h"
|
|
15
|
-
#endif
|
|
10
|
+
#import <ExpoModulesCore/Swift.h>
|
|
16
11
|
|
|
17
12
|
@interface EXModuleRegistryAdapter ()
|
|
18
13
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// Swift compatibility headers (e.g. `ExpoModulesCore-Swift.h`) are not available in headers,
|
|
13
13
|
// so we use class forward declaration here. Swift header must be imported in the `.m` file.
|
|
14
14
|
@class SwiftInteropBridge;
|
|
15
|
+
@protocol ModulesProviderObjCProtocol;
|
|
15
16
|
|
|
16
17
|
NS_SWIFT_NAME(NativeModulesProxy)
|
|
17
18
|
@interface EXNativeModulesProxy : NSObject <RCTBridgeModule>
|
|
@@ -21,4 +22,9 @@ NS_SWIFT_NAME(NativeModulesProxy)
|
|
|
21
22
|
- (nonnull instancetype)init;
|
|
22
23
|
- (nonnull instancetype)initWithModuleRegistry:(nullable EXModuleRegistry *)moduleRegistry;
|
|
23
24
|
|
|
25
|
+
- (void)callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNameOrKey arguments:(NSArray *)arguments resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
|
|
26
|
+
- (id)callMethodSync:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray *)arguments;
|
|
27
|
+
|
|
28
|
+
+ (id<ModulesProviderObjCProtocol>)getExpoModulesProvider;
|
|
29
|
+
|
|
24
30
|
@end
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
#import <React/RCTModuleData.h>
|
|
9
9
|
#import <React/RCTEventDispatcherProtocol.h>
|
|
10
10
|
|
|
11
|
+
#import <jsi/jsi.h>
|
|
12
|
+
|
|
11
13
|
#import <ExpoModulesCore/EXNativeModulesProxy.h>
|
|
12
14
|
#import <ExpoModulesCore/EXEventEmitter.h>
|
|
13
15
|
#import <ExpoModulesCore/EXViewManager.h>
|
|
@@ -15,12 +17,8 @@
|
|
|
15
17
|
#import <ExpoModulesCore/EXViewManagerAdapterClassesRegistry.h>
|
|
16
18
|
#import <ExpoModulesCore/EXModuleRegistryProvider.h>
|
|
17
19
|
#import <ExpoModulesCore/EXReactNativeEventEmitter.h>
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
#import <ExpoModulesCore/ExpoModulesCore-Swift.h>
|
|
21
|
-
#else
|
|
22
|
-
#import "ExpoModulesCore-Swift.h"
|
|
23
|
-
#endif
|
|
20
|
+
#import <ExpoModulesCore/JSIInstaller.h>
|
|
21
|
+
#import <ExpoModulesCore/Swift.h>
|
|
24
22
|
|
|
25
23
|
static const NSString *exportedMethodsNamesKeyPath = @"exportedMethods";
|
|
26
24
|
static const NSString *viewManagersNamesKeyPath = @"viewManagersNames";
|
|
@@ -37,6 +35,12 @@ static const NSString *methodInfoArgumentsCountKey = @"argumentsCount";
|
|
|
37
35
|
|
|
38
36
|
@end
|
|
39
37
|
|
|
38
|
+
@interface RCTBridge (JSIRuntime)
|
|
39
|
+
|
|
40
|
+
- (void *)runtime;
|
|
41
|
+
|
|
42
|
+
@end
|
|
43
|
+
|
|
40
44
|
@interface RCTComponentData (EXNativeModulesProxy)
|
|
41
45
|
|
|
42
46
|
- (instancetype)initWithManagerClass:(Class)managerClass bridge:(RCTBridge *)bridge eventDispatcher:(id<RCTEventDispatcherProtocol>) eventDispatcher; // available in RN 0.65+
|
|
@@ -68,7 +72,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
68
72
|
{
|
|
69
73
|
if (self = [super init]) {
|
|
70
74
|
_exModuleRegistry = moduleRegistry != nil ? moduleRegistry : [[EXModuleRegistryProvider new] moduleRegistry];
|
|
71
|
-
_swiftInteropBridge = [[SwiftInteropBridge alloc] initWithModulesProvider:[
|
|
75
|
+
_swiftInteropBridge = [[SwiftInteropBridge alloc] initWithModulesProvider:[EXNativeModulesProxy getExpoModulesProvider] legacyModuleRegistry:_exModuleRegistry];
|
|
72
76
|
_exportedMethodsKeys = [NSMutableDictionary dictionary];
|
|
73
77
|
_exportedMethodsReverseKeys = [NSMutableDictionary dictionary];
|
|
74
78
|
_ownsModuleRegistry = moduleRegistry == nil;
|
|
@@ -93,6 +97,9 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
93
97
|
|
|
94
98
|
- (NSDictionary *)constantsToExport
|
|
95
99
|
{
|
|
100
|
+
// Install the TurboModule implementation of the proxy.
|
|
101
|
+
[self installExpoTurboModules];
|
|
102
|
+
|
|
96
103
|
NSMutableDictionary <NSString *, id> *exportedModulesConstants = [NSMutableDictionary dictionary];
|
|
97
104
|
// Grab all the constants exported by modules
|
|
98
105
|
for (EXExportedModule *exportedModule in [_exModuleRegistry getAllExportedModules]) {
|
|
@@ -121,7 +128,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
// Add entries from Swift modules
|
|
124
|
-
[exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge
|
|
131
|
+
[exportedMethodsNamesAccumulator addEntriesFromDictionary:[_swiftInteropBridge exportedFunctionNames]];
|
|
125
132
|
|
|
126
133
|
// Also, add `viewManagersNames` for sanity check and testing purposes -- with names we know what managers to mock on UIManager
|
|
127
134
|
NSArray<EXViewManager *> *viewManagers = [_exModuleRegistry getAllViewManagers];
|
|
@@ -151,7 +158,7 @@ RCT_EXPORT_MODULE(NativeUnimoduleProxy)
|
|
|
151
158
|
RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNameOrKey arguments:(NSArray *)arguments resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
152
159
|
{
|
|
153
160
|
if ([_swiftInteropBridge hasModule:moduleName]) {
|
|
154
|
-
[_swiftInteropBridge
|
|
161
|
+
[_swiftInteropBridge callFunction:methodNameOrKey onModule:moduleName withArgs:arguments resolve:resolve reject:reject];
|
|
155
162
|
return;
|
|
156
163
|
}
|
|
157
164
|
EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
|
|
@@ -186,10 +193,20 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
186
193
|
});
|
|
187
194
|
}
|
|
188
195
|
|
|
189
|
-
|
|
196
|
+
- (id)callMethodSync:(NSString *)moduleName methodName:(NSString *)methodName arguments:(NSArray *)arguments
|
|
197
|
+
{
|
|
198
|
+
if ([_swiftInteropBridge hasModule:moduleName]) {
|
|
199
|
+
return [_swiftInteropBridge callFunctionSync:methodName onModule:moduleName withArgs:arguments];
|
|
200
|
+
}
|
|
201
|
+
return (id)kCFNull;
|
|
202
|
+
}
|
|
190
203
|
|
|
191
|
-
-
|
|
204
|
+
#pragma mark - Statics
|
|
205
|
+
|
|
206
|
+
+ (id<ModulesProviderObjCProtocol>)getExpoModulesProvider
|
|
192
207
|
{
|
|
208
|
+
// Dynamically gets the modules provider class.
|
|
209
|
+
// NOTE: This needs to be versioned in Expo Go.
|
|
193
210
|
Class generatedExpoModulesProvider = NSClassFromString(@"ExpoModulesProvider");
|
|
194
211
|
// Checks if `ExpoModulesProvider` was generated
|
|
195
212
|
if (generatedExpoModulesProvider) {
|
|
@@ -199,6 +216,8 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
199
216
|
}
|
|
200
217
|
}
|
|
201
218
|
|
|
219
|
+
#pragma mark - Privates
|
|
220
|
+
|
|
202
221
|
- (void)registerExpoModulesInBridge:(RCTBridge *)bridge
|
|
203
222
|
{
|
|
204
223
|
// Registering expo modules in bridge is needed only when the proxy module owns the registry
|
|
@@ -255,8 +274,10 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
255
274
|
// components in UIManager — we need to register them on our own.
|
|
256
275
|
[self registerComponentDataForModuleClasses:additionalModuleClasses inBridge:bridge];
|
|
257
276
|
|
|
258
|
-
// Get the newly created instance of `EXReactEventEmitter` bridge module
|
|
277
|
+
// Get the newly created instance of `EXReactEventEmitter` bridge module,
|
|
278
|
+
// pass event names supported by Swift modules and register it in legacy modules registry.
|
|
259
279
|
EXReactNativeEventEmitter *eventEmitter = [bridge moduleForClass:[EXReactNativeEventEmitter class]];
|
|
280
|
+
[eventEmitter setSwiftInteropBridge:_swiftInteropBridge];
|
|
260
281
|
[_exModuleRegistry registerInternalModule:eventEmitter];
|
|
261
282
|
|
|
262
283
|
// Let the modules consume the registry :)
|
|
@@ -345,4 +366,16 @@ RCT_EXPORT_METHOD(callMethod:(NSString *)moduleName methodNameOrKey:(id)methodNa
|
|
|
345
366
|
}
|
|
346
367
|
}
|
|
347
368
|
|
|
369
|
+
/**
|
|
370
|
+
Installs expo modules in JSI runtime.
|
|
371
|
+
*/
|
|
372
|
+
- (void)installExpoTurboModules
|
|
373
|
+
{
|
|
374
|
+
facebook::jsi::Runtime *runtime = [_bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<facebook::jsi::Runtime *>(_bridge.runtime) : NULL;
|
|
375
|
+
|
|
376
|
+
if (runtime) {
|
|
377
|
+
expo::installRuntimeObjects(*runtime, _bridge.jsCallInvoker, self);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
348
381
|
@end
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
#import <ExpoModulesCore/EXModuleRegistryConsumer.h>
|
|
8
8
|
#import <ExpoModulesCore/EXBridgeModule.h>
|
|
9
9
|
|
|
10
|
+
// Swift compatibility headers (e.g. `ExpoModulesCore-Swift.h`) are not available in headers,
|
|
11
|
+
// so we use class forward declaration here. Swift header must be imported in the `.m` file.
|
|
12
|
+
@class SwiftInteropBridge;
|
|
13
|
+
|
|
10
14
|
@interface EXReactNativeEventEmitter : RCTEventEmitter <EXInternalModule, EXBridgeModule, EXModuleRegistryConsumer, EXEventEmitterService>
|
|
11
15
|
|
|
16
|
+
@property (nonatomic, strong) SwiftInteropBridge *swiftInteropBridge;
|
|
17
|
+
|
|
12
18
|
@end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#import <ExpoModulesCore/EXEventEmitter.h>
|
|
5
5
|
#import <ExpoModulesCore/EXExportedModule.h>
|
|
6
6
|
#import <ExpoModulesCore/EXModuleRegistry.h>
|
|
7
|
+
#import <ExpoModulesCore/Swift.h>
|
|
7
8
|
|
|
8
9
|
@interface EXReactNativeEventEmitter ()
|
|
9
10
|
|
|
@@ -42,6 +43,10 @@
|
|
|
42
43
|
- (NSArray<NSString *> *)supportedEvents
|
|
43
44
|
{
|
|
44
45
|
NSMutableSet<NSString *> *eventsAccumulator = [NSMutableSet set];
|
|
46
|
+
|
|
47
|
+
if (_swiftInteropBridge) {
|
|
48
|
+
[eventsAccumulator addObjectsFromArray:[_swiftInteropBridge getSupportedEvents]];
|
|
49
|
+
}
|
|
45
50
|
for (EXExportedModule *exportedModule in [_exModuleRegistry getAllExportedModules]) {
|
|
46
51
|
if ([exportedModule conformsToProtocol:@protocol(EXEventEmitter)]) {
|
|
47
52
|
id<EXEventEmitter> eventEmitter = (id<EXEventEmitter>)exportedModule;
|
|
@@ -54,6 +59,11 @@
|
|
|
54
59
|
RCT_EXPORT_METHOD(addProxiedListener:(NSString *)moduleName eventName:(NSString *)eventName)
|
|
55
60
|
{
|
|
56
61
|
[self addListener:eventName];
|
|
62
|
+
|
|
63
|
+
if ([_swiftInteropBridge hasModule:moduleName]) {
|
|
64
|
+
[_swiftInteropBridge modifyEventListenersCount:moduleName count:1];
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
57
67
|
// Validate module
|
|
58
68
|
EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
|
|
59
69
|
|
|
@@ -90,6 +100,11 @@ RCT_EXPORT_METHOD(addProxiedListener:(NSString *)moduleName eventName:(NSString
|
|
|
90
100
|
RCT_EXPORT_METHOD(removeProxiedListeners:(NSString *)moduleName count:(double)count)
|
|
91
101
|
{
|
|
92
102
|
[self removeListeners:count];
|
|
103
|
+
|
|
104
|
+
if ([_swiftInteropBridge hasModule:moduleName]) {
|
|
105
|
+
[_swiftInteropBridge modifyEventListenersCount:moduleName count:-count];
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
93
108
|
// Validate module
|
|
94
109
|
EXExportedModule *module = [_exModuleRegistry getExportedModuleForName:moduleName];
|
|
95
110
|
|
|
@@ -2,7 +2,7 @@ import UIKit
|
|
|
2
2
|
/**
|
|
3
3
|
The app context is an interface to a single Expo app.
|
|
4
4
|
*/
|
|
5
|
-
public class AppContext {
|
|
5
|
+
public final class AppContext {
|
|
6
6
|
/**
|
|
7
7
|
The module registry for the app context.
|
|
8
8
|
*/
|
|
@@ -71,6 +71,13 @@ public class AppContext {
|
|
|
71
71
|
return legacyModule(implementing: EXUtilitiesInterface.self)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
Provides access to the event emitter from legacy module registry.
|
|
76
|
+
*/
|
|
77
|
+
public var eventEmitter: EXEventEmitterService? {
|
|
78
|
+
return legacyModule(implementing: EXEventEmitterService.self)
|
|
79
|
+
}
|
|
80
|
+
|
|
74
81
|
/**
|
|
75
82
|
Starts listening to `UIApplication` notifications.
|
|
76
83
|
*/
|
|
@@ -108,4 +115,10 @@ public class AppContext {
|
|
|
108
115
|
NotificationCenter.default.removeObserver(self)
|
|
109
116
|
moduleRegistry.post(event: .appContextDestroys)
|
|
110
117
|
}
|
|
118
|
+
|
|
119
|
+
// MARK: Errors
|
|
120
|
+
|
|
121
|
+
struct DeallocatedAppContextError: CodedError {
|
|
122
|
+
var description: String = "The app context has been deallocated."
|
|
123
|
+
}
|
|
111
124
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
A protocol for classes/structs accepted as an argument of functions.
|
|
5
|
+
*/
|
|
6
|
+
public protocol AnyArgument {}
|
|
7
|
+
|
|
8
|
+
// Extend the primitive types — these may come from React Native bridge.
|
|
9
|
+
extension Bool: AnyArgument {}
|
|
10
|
+
extension Int: AnyArgument {}
|
|
11
|
+
extension Double: AnyArgument {}
|
|
12
|
+
extension String: AnyArgument {}
|
|
13
|
+
extension Array: AnyArgument {}
|
|
14
|
+
extension Dictionary: AnyArgument {}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
A protocol whose intention is to wrap function's argument type
|
|
5
|
+
to keep its real signature and not type-erase it by the compiler.
|
|
6
|
+
*/
|
|
7
|
+
internal protocol AnyArgumentType: CustomStringConvertible {
|
|
8
|
+
/**
|
|
9
|
+
Casts given any value to the wrapped type and returns as `Any`.
|
|
10
|
+
NOTE: It may not be just simple type-casting (e.g. when the wrapped type conforms to `ConvertibleArgument`).
|
|
11
|
+
*/
|
|
12
|
+
func cast<ArgType>(_ value: ArgType) throws -> Any
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
Factory creating an instance of the argument type wrapper conforming to `AnyArgumentType`.
|
|
5
|
+
Depending on the given type, it may return one of `ArrayArgumentType`, `OptionalArgumentType`, `ConvertibleArgumentType`, etc.
|
|
6
|
+
*/
|
|
7
|
+
internal func ArgumentType<T>(_ type: T.Type) -> AnyArgumentType {
|
|
8
|
+
if let ArrayType = T.self as? AnyArrayArgument.Type {
|
|
9
|
+
return ArrayArgumentType(elementType: ArrayType.getElementArgumentType())
|
|
10
|
+
}
|
|
11
|
+
if let OptionalType = T.self as? AnyOptionalArgument.Type {
|
|
12
|
+
return OptionalArgumentType(wrappedType: OptionalType.getWrappedArgumentType())
|
|
13
|
+
}
|
|
14
|
+
if let ConvertibleType = T.self as? ConvertibleArgument.Type {
|
|
15
|
+
return ConvertibleArgumentType(innerType: ConvertibleType)
|
|
16
|
+
}
|
|
17
|
+
if let EnumType = T.self as? EnumArgument.Type {
|
|
18
|
+
return EnumArgumentType(innerType: EnumType)
|
|
19
|
+
}
|
|
20
|
+
if T.self is Promise.Type {
|
|
21
|
+
return PromiseArgumentType()
|
|
22
|
+
}
|
|
23
|
+
return RawArgumentType(innerType: T.self)
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright 2018-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
A protocol that allows custom classes or structs to be used as function arguments.
|
|
5
|
+
It requires static `convert(from:)` function that knows how to convert incoming
|
|
6
|
+
value of `Any` type to the type implemented by this protocol. It should throw an error
|
|
7
|
+
when the value is not recognized, is invalid or doesn't meet type requirements.
|
|
8
|
+
*/
|
|
9
|
+
public protocol ConvertibleArgument: AnyArgument {
|
|
10
|
+
/**
|
|
11
|
+
Converts any value to the instance of its class (or struct).
|
|
12
|
+
Throws an error when given value cannot be converted.
|
|
13
|
+
*/
|
|
14
|
+
static func convert(from value: Any?) throws -> Self
|
|
15
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Copyright 2018-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
import UIKit
|
|
4
|
+
import CoreGraphics
|
|
5
|
+
|
|
6
|
+
/// Here we extend some common iOS types to implement `ConvertibleArgument` protocol and
|
|
7
|
+
/// describe how they can be converted from primitive types received from JavaScript runtime.
|
|
8
|
+
/// This allows these types to be used as argument types of functions callable from JavaScript.
|
|
9
|
+
/// As an example, when the `CGPoint` type is used as an argument type, its instance can be
|
|
10
|
+
/// created from an array of two doubles or an object with `x` and `y` fields.
|
|
11
|
+
|
|
12
|
+
// MARK: - UIKit
|
|
13
|
+
|
|
14
|
+
extension UIColor: ConvertibleArgument {
|
|
15
|
+
public static func convert(from value: Any?) throws -> Self {
|
|
16
|
+
if let value = value as? String {
|
|
17
|
+
return try Conversions.toColor(hexString: value) as! Self
|
|
18
|
+
}
|
|
19
|
+
if let components = value as? [Double] {
|
|
20
|
+
let alpha = components.count > 3 ? components[3] : 1.0
|
|
21
|
+
return Self.init(red: components[0], green: components[1], blue: components[2], alpha: alpha)
|
|
22
|
+
}
|
|
23
|
+
if let value = value as? Int {
|
|
24
|
+
return try Conversions.toColor(argb: UInt64(value)) as! Self
|
|
25
|
+
}
|
|
26
|
+
throw Conversions.ConvertingError<UIColor>(value: value)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// MARK: - CoreGraphics
|
|
31
|
+
|
|
32
|
+
extension CGPoint: ConvertibleArgument {
|
|
33
|
+
public static func convert(from value: Any?) throws -> CGPoint {
|
|
34
|
+
if let value = value as? [Double], value.count == 2 {
|
|
35
|
+
return CGPoint(x: value[0], y: value[1])
|
|
36
|
+
}
|
|
37
|
+
if let value = value as? [String: Any] {
|
|
38
|
+
let args = try Conversions.pickValues(from: value, byKeys: ["x", "y"], as: Double.self)
|
|
39
|
+
return CGPoint(x: args[0], y: args[1])
|
|
40
|
+
}
|
|
41
|
+
throw Conversions.ConvertingError<CGPoint>(value: value)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
extension CGSize: ConvertibleArgument {
|
|
46
|
+
public static func convert(from value: Any?) throws -> CGSize {
|
|
47
|
+
if let value = value as? [Double], value.count == 2 {
|
|
48
|
+
return CGSize(width: value[0], height: value[1])
|
|
49
|
+
}
|
|
50
|
+
if let value = value as? [String: Any] {
|
|
51
|
+
let args = try Conversions.pickValues(from: value, byKeys: ["width", "height"], as: Double.self)
|
|
52
|
+
return CGSize(width: args[0], height: args[1])
|
|
53
|
+
}
|
|
54
|
+
throw Conversions.ConvertingError<CGSize>(value: value)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
extension CGVector: ConvertibleArgument {
|
|
59
|
+
public static func convert(from value: Any?) throws -> CGVector {
|
|
60
|
+
if let value = value as? [Double], value.count == 2 {
|
|
61
|
+
return CGVector(dx: value[0], dy: value[1])
|
|
62
|
+
}
|
|
63
|
+
if let value = value as? [String: Any] {
|
|
64
|
+
let args = try Conversions.pickValues(from: value, byKeys: ["dx", "dy"], as: Double.self)
|
|
65
|
+
return CGVector(dx: args[0], dy: args[1])
|
|
66
|
+
}
|
|
67
|
+
throw Conversions.ConvertingError<CGVector>(value: value)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
extension CGRect: ConvertibleArgument {
|
|
72
|
+
public static func convert(from value: Any?) throws -> CGRect {
|
|
73
|
+
if let value = value as? [Double], value.count == 4 {
|
|
74
|
+
return CGRect(x: value[0], y: value[1], width: value[2], height: value[3])
|
|
75
|
+
}
|
|
76
|
+
if let value = value as? [String: Any] {
|
|
77
|
+
let args = try Conversions.pickValues(from: value, byKeys: ["x", "y", "width", "height"], as: Double.self)
|
|
78
|
+
return CGRect(x: args[0], y: args[1], width: args[2], height: args[3])
|
|
79
|
+
}
|
|
80
|
+
throw Conversions.ConvertingError<CGRect>(value: value)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
extension CGColor: ConvertibleArgument {
|
|
85
|
+
public static func convert(from value: Any?) throws -> Self {
|
|
86
|
+
do {
|
|
87
|
+
return try UIColor.convert(from: value).cgColor as! Self
|
|
88
|
+
} catch _ as Conversions.ConvertingError<UIColor> {
|
|
89
|
+
// Rethrow `ConvertingError` with proper type
|
|
90
|
+
throw Conversions.ConvertingError<CGColor>(value: value)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
An argument type representing array types. Requires the argument type for
|
|
5
|
+
array's element type as it delegates casting to that type for each element in the array.
|
|
6
|
+
*/
|
|
7
|
+
internal struct ArrayArgumentType: AnyArgumentType {
|
|
8
|
+
let elementType: AnyArgumentType
|
|
9
|
+
|
|
10
|
+
func cast<ArgType>(_ value: ArgType) throws -> Any {
|
|
11
|
+
if let value = value as? [Any] {
|
|
12
|
+
return try value.map { try elementType.cast($0) }
|
|
13
|
+
}
|
|
14
|
+
// We should probably throw an error if we get here. On the other side, the array type
|
|
15
|
+
// requirement can be more loosen so we can try to arrayize values that are not arrays.
|
|
16
|
+
return [try elementType.cast(value)]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var description: String {
|
|
20
|
+
"[\(elementType.description)]"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
A type-erased protocol used to recognize arrays with elements of argument-compatible type.
|
|
26
|
+
`Array` is a generic type, so it's impossible to check the inheritance directly.
|
|
27
|
+
*/
|
|
28
|
+
internal protocol AnyArrayArgument: AnyArgument {
|
|
29
|
+
/**
|
|
30
|
+
Exposes the `Element` generic type wrapped by the argument type to preserve its metadata.
|
|
31
|
+
*/
|
|
32
|
+
static func getElementArgumentType() -> AnyArgumentType
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
Extends the `Array` type to expose its generic `Element` as an argument type.
|
|
37
|
+
*/
|
|
38
|
+
extension Array: AnyArrayArgument where Element: AnyArgument {
|
|
39
|
+
static func getElementArgumentType() -> AnyArgumentType {
|
|
40
|
+
return ArgumentType(Element.self)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
An argument type that wraps any type conforming to `ConvertibleArgument` protocol.
|
|
5
|
+
*/
|
|
6
|
+
internal struct ConvertibleArgumentType: AnyArgumentType {
|
|
7
|
+
let innerType: ConvertibleArgument.Type
|
|
8
|
+
|
|
9
|
+
func cast<ArgType>(_ value: ArgType) throws -> Any {
|
|
10
|
+
return try innerType.convert(from: value)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
var description: String {
|
|
14
|
+
String(describing: innerType.self)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
An argument type representing an enum that conforms to `EnumArgument`.
|
|
5
|
+
*/
|
|
6
|
+
internal struct EnumArgumentType: AnyArgumentType {
|
|
7
|
+
let innerType: EnumArgument.Type
|
|
8
|
+
|
|
9
|
+
func cast<ArgType>(_ value: ArgType) throws -> Any {
|
|
10
|
+
return try innerType.create(fromRawValue: value)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
var description: String {
|
|
14
|
+
"Enum<\(innerType)>"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
A protocol that allows converting raw values to enum cases.
|
|
20
|
+
*/
|
|
21
|
+
public protocol EnumArgument: AnyArgument {
|
|
22
|
+
/**
|
|
23
|
+
Tries to create an enum case using given raw value.
|
|
24
|
+
May throw errors, e.g. when the raw value doesn't match any case.
|
|
25
|
+
*/
|
|
26
|
+
static func create<ArgType>(fromRawValue rawValue: ArgType) throws -> Self
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
Returns an array of all raw values available in the enum.
|
|
30
|
+
*/
|
|
31
|
+
static var allRawValues: [Any] { get }
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
Type-erased enum's raw value.
|
|
35
|
+
*/
|
|
36
|
+
var anyRawValue: Any { get }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
Extension for `EnumArgument` that also conforms to `RawRepresentable`.
|
|
41
|
+
This constraint allows us to reference the associated `RawValue` type.
|
|
42
|
+
*/
|
|
43
|
+
public extension EnumArgument where Self: RawRepresentable, Self: Hashable {
|
|
44
|
+
static func create<ArgType>(fromRawValue rawValue: ArgType) throws -> Self {
|
|
45
|
+
guard let rawValue = rawValue as? RawValue else {
|
|
46
|
+
throw EnumCastingError(type: RawValue.self, value: rawValue)
|
|
47
|
+
}
|
|
48
|
+
guard let enumCase = Self.init(rawValue: rawValue) else {
|
|
49
|
+
throw EnumNoSuchValueError(type: Self.self, value: rawValue)
|
|
50
|
+
}
|
|
51
|
+
return enumCase
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
var anyRawValue: Any {
|
|
55
|
+
rawValue
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static var allRawValues: [Any] {
|
|
59
|
+
// Be careful — it operates on unsafe pointers!
|
|
60
|
+
let sequence = AnySequence { () -> AnyIterator<RawValue> in
|
|
61
|
+
var raw = 0
|
|
62
|
+
return AnyIterator {
|
|
63
|
+
let current: Self? = withUnsafePointer(to: &raw) { ptr in
|
|
64
|
+
ptr.withMemoryRebound(to: Self.self, capacity: 1) { $0.pointee }
|
|
65
|
+
}
|
|
66
|
+
guard let value = current?.rawValue else {
|
|
67
|
+
return nil
|
|
68
|
+
}
|
|
69
|
+
raw += 1
|
|
70
|
+
return value
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return Array(sequence)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
An error that is thrown when the value cannot be casted to associated `RawValue`.
|
|
79
|
+
*/
|
|
80
|
+
internal struct EnumCastingError: CodedError {
|
|
81
|
+
let type: Any.Type
|
|
82
|
+
let value: Any
|
|
83
|
+
|
|
84
|
+
var description: String {
|
|
85
|
+
"Cannot cast value `\(value)` to expected type `\(type)`"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
An error that is thrown when the value doesn't match any available case.
|
|
91
|
+
*/
|
|
92
|
+
internal struct EnumNoSuchValueError: CodedError {
|
|
93
|
+
let type: EnumArgument.Type
|
|
94
|
+
let value: Any
|
|
95
|
+
|
|
96
|
+
var allRawValuesFormatted: String {
|
|
97
|
+
return type.allRawValues
|
|
98
|
+
.map { "`\($0)`" }
|
|
99
|
+
.joined(separator: ", ")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var description: String {
|
|
103
|
+
"Cannot create `\(type)` enum from value `\(value)`. It must be one of: \(allRawValuesFormatted)"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Copyright 2021-present 650 Industries. All rights reserved.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
An argument type that represents an optional type, which allows `nil` to be passed when casting.
|
|
5
|
+
Requires the argument type for optional's unwrapped type as it delegates casting to that type for non-nil values.
|
|
6
|
+
*/
|
|
7
|
+
internal struct OptionalArgumentType: AnyArgumentType {
|
|
8
|
+
let wrappedType: AnyArgumentType
|
|
9
|
+
|
|
10
|
+
func cast<ArgType>(_ value: ArgType) throws -> Any {
|
|
11
|
+
if Optional.isNil(value) {
|
|
12
|
+
return Optional<Any>.none as Any
|
|
13
|
+
}
|
|
14
|
+
return try wrappedType.cast(value)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var description: String {
|
|
18
|
+
"\(wrappedType)?"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
A type-erased protocol used to recognize if the generic type is an optional type.
|
|
24
|
+
`Optional` is a generic enum, so it's impossible to check the inheritance directly.
|
|
25
|
+
*/
|
|
26
|
+
internal protocol AnyOptionalArgument: AnyArgument {
|
|
27
|
+
/**
|
|
28
|
+
Exposes the `Wrapped` generic type wrapped by the argument type to preserve its metadata.`
|
|
29
|
+
*/
|
|
30
|
+
static func getWrappedArgumentType() -> AnyArgumentType
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
Make generic `Optional` implement non-generic `AnyOptional` and add handy check against type-erased `nil`.
|
|
35
|
+
*/
|
|
36
|
+
extension Optional: AnyOptionalArgument {
|
|
37
|
+
static func getWrappedArgumentType() -> AnyArgumentType {
|
|
38
|
+
return ArgumentType(Wrapped.self)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static func isNil(_ object: Wrapped) -> Bool {
|
|
42
|
+
switch object as Any {
|
|
43
|
+
case Optional<Any>.none:
|
|
44
|
+
return true
|
|
45
|
+
default:
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|