1// Copyright © 2018 650 Industries. All rights reserved. 2 3#import <objc/runtime.h> 4 5#import <ABI49_0_0ExpoModulesCore/ABI49_0_0EXModuleRegistry.h> 6#import <ABI49_0_0ExpoModulesCore/ABI49_0_0EXModuleRegistryConsumer.h> 7 8@interface ABI49_0_0EXModuleRegistry () 9 10@property (nonatomic, weak) id<ABI49_0_0EXModuleRegistryDelegate> delegate; 11 12@property NSMutableSet<id<ABI49_0_0EXInternalModule>> *internalModulesSet; 13@property NSMapTable<Protocol *, id<ABI49_0_0EXInternalModule>> *internalModules; 14@property NSMapTable<Protocol *, NSMutableArray<id<ABI49_0_0EXInternalModule>> *> *internalModulesPreResolution; 15@property NSMapTable<Class, ABI49_0_0EXExportedModule *> *exportedModulesByClass; 16@property NSMutableDictionary<const NSString *, ABI49_0_0EXExportedModule *> *exportedModules; 17@property NSMutableDictionary<const NSString *, id> *singletonModules; 18 19@property NSPointerArray *registryConsumers; 20 21@end 22 23@implementation ABI49_0_0EXModuleRegistry 24 25# pragma mark - Lifecycle 26 27- (instancetype)init 28{ 29 if (self = [super init]) { 30 _internalModulesPreResolution = [NSMapTable weakToStrongObjectsMapTable]; 31 _exportedModulesByClass = [NSMapTable weakToWeakObjectsMapTable]; 32 _exportedModules = [NSMutableDictionary dictionary]; 33 _singletonModules = [NSMutableDictionary dictionary]; 34 _registryConsumers = [NSPointerArray weakObjectsPointerArray]; 35 } 36 return self; 37} 38 39- (instancetype)initWithInternalModules:(NSSet<id<ABI49_0_0EXInternalModule>> *)internalModules 40 exportedModules:(NSSet<ABI49_0_0EXExportedModule *> *)exportedModules 41 singletonModules:(NSSet *)singletonModules 42{ 43 if (self = [self init]) { 44 for (id<ABI49_0_0EXInternalModule> internalModule in internalModules) { 45 [self registerInternalModule:internalModule]; 46 } 47 48 for (ABI49_0_0EXExportedModule *exportedModule in exportedModules) { 49 [self registerExportedModule:exportedModule]; 50 } 51 52 for (id singletonModule in singletonModules) { 53 [self registerSingletonModule:singletonModule]; 54 } 55 } 56 return self; 57} 58 59- (void)setDelegate:(id<ABI49_0_0EXModuleRegistryDelegate>)delegate 60{ 61 _delegate = delegate; 62} 63 64// Fills in _internalModules and _internalModulesSet 65- (void)resolveInternalModulesConflicts 66{ 67 if (_internalModules) { 68 // Conflict resolution has already been completed. 69 return; 70 } 71 72 _internalModules = [NSMapTable weakToStrongObjectsMapTable]; 73 _internalModulesSet = [NSMutableSet new]; 74 for (Protocol *protocol in _internalModulesPreResolution) { 75 NSArray<id<ABI49_0_0EXInternalModule>> *conflictingModules = [_internalModulesPreResolution objectForKey:protocol]; 76 77 id<ABI49_0_0EXInternalModule> resolvedModule; 78 if ([conflictingModules count] > 1 && _delegate) { 79 resolvedModule = [_delegate pickInternalModuleImplementingInterface:protocol fromAmongModules:conflictingModules]; 80 } else { 81 resolvedModule = [conflictingModules lastObject]; 82 } 83 84 [_internalModules setObject:resolvedModule forKey:protocol]; 85 [self maybeAddRegistryConsumer:resolvedModule]; 86 [_internalModulesSet addObject:resolvedModule]; 87 } 88 89 _internalModulesPreResolution = nil; // Remove references to discarded modules 90} 91 92- (void)initialize 93{ 94 [self resolveInternalModulesConflicts]; 95 for (id<ABI49_0_0EXModuleRegistryConsumer> registryConsumer in _registryConsumers) { 96 [registryConsumer setModuleRegistry:self]; 97 } 98} 99 100# pragma mark - Registering modules 101 102- (void)registerInternalModule:(id<ABI49_0_0EXInternalModule>)internalModule 103{ 104 for (Protocol *exportedInterface in [[internalModule class] exportedInterfaces]) { 105 if (_internalModules) { 106 id<ABI49_0_0EXInternalModule> resolvedModule = internalModule; 107 if (_delegate && [_internalModules objectForKey:exportedInterface]) { 108 id<ABI49_0_0EXInternalModule> oldModule = [_internalModules objectForKey:exportedInterface]; 109 resolvedModule = [_delegate pickInternalModuleImplementingInterface:exportedInterface fromAmongModules:@[oldModule, internalModule]]; 110 } 111 [_internalModules setObject:resolvedModule forKey:exportedInterface]; 112 [self maybeAddRegistryConsumer:resolvedModule]; 113 [_internalModulesSet addObject:resolvedModule]; 114 } else { 115 if (![_internalModulesPreResolution objectForKey:exportedInterface]) { 116 [_internalModulesPreResolution setObject:[NSMutableArray array] forKey:exportedInterface]; 117 } 118 119 [[_internalModulesPreResolution objectForKey:exportedInterface] addObject:internalModule]; 120 } 121 } 122} 123 124- (void)registerExportedModule:(ABI49_0_0EXExportedModule *)exportedModule 125{ 126 const NSString *exportedModuleName = [[exportedModule class] exportedModuleName]; 127 if (_exportedModules[exportedModuleName]) { 128 ABI49_0_0EXLogInfo(@"Module %@ overrides %@ as the module exported as %@.", exportedModule, _exportedModules[exportedModuleName], exportedModuleName); 129 } 130 131 _exportedModules[exportedModuleName] = exportedModule; 132 [_exportedModulesByClass setObject:exportedModule forKey:[exportedModule class]]; 133 [self maybeAddRegistryConsumer:exportedModule]; 134} 135 136- (void)registerSingletonModule:(id)singletonModule 137{ 138 if ([[singletonModule class] respondsToSelector:@selector(name)]) { 139 #pragma clang diagnostic push 140 #pragma clang diagnostic ignored "-Wobjc-method-access" 141 [_singletonModules setObject:singletonModule forKey:[[singletonModule class] name]]; 142 #pragma clang diagnostic pop 143 } else { 144 ABI49_0_0EXLogWarn(@"One of the singleton modules does not respond to +(NSString *)name selector. This probably means you're either try to pass a strange object as a singleton module (it won't get registered in the module registry, sorry) or the ABI49_0_0EXSingletonModule interface and the ABI49_0_0EXModuleRegistry implementations versions are out of sync, which means things will probably not work as expected."); 145 } 146} 147 148- (void)maybeAddRegistryConsumer:(id)maybeConsumer 149{ 150 if ([maybeConsumer conformsToProtocol:@protocol(ABI49_0_0EXModuleRegistryConsumer)]) { 151 [self addRegistryConsumer:(id<ABI49_0_0EXModuleRegistryConsumer>)maybeConsumer]; 152 } 153} 154 155- (void)addRegistryConsumer:(id<ABI49_0_0EXModuleRegistryConsumer>)registryConsumer 156{ 157 void *ptr = (__bridge void * _Nullable)registryConsumer; 158 159 for (id consumerPtr in _registryConsumers) { 160 if (consumerPtr == ptr) { 161 return; 162 } 163 } 164 [_registryConsumers addPointer:ptr]; 165} 166 167# pragma mark - Registry API 168 169- (id)getModuleImplementingProtocol:(Protocol *)protocol 170{ 171 [self resolveInternalModulesConflicts]; 172 return [_internalModules objectForKey:protocol]; 173} 174 175- (ABI49_0_0EXExportedModule *)getExportedModuleForName:(NSString *)name 176{ 177 return _exportedModules[name]; 178} 179 180- (ABI49_0_0EXExportedModule *)getExportedModuleOfClass:(Class)moduleClass 181{ 182 return [_exportedModulesByClass objectForKey:moduleClass]; 183} 184 185- (id)getSingletonModuleForName:(NSString *)singletonModuleName 186{ 187 return [_singletonModules objectForKey:singletonModuleName]; 188} 189 190- (NSArray<id<ABI49_0_0EXInternalModule>> *)getAllInternalModules 191{ 192 [self resolveInternalModulesConflicts]; 193 return [_internalModulesSet allObjects]; 194} 195 196- (NSArray<ABI49_0_0EXExportedModule *> *)getAllExportedModules 197{ 198 return [_exportedModules allValues]; 199} 200 201- (NSArray *)getAllSingletonModules 202{ 203 return [_singletonModules allValues]; 204} 205 206@end 207