1 // Copyright 2022-present 650 Industries. All rights reserved. 2 3 /** 4 Type-erased protocol for synchronous functions. 5 */ 6 internal protocol AnySyncFunctionComponent: AnyFunction { 7 /** 8 Calls the function synchronously with given arguments. 9 - Parameters: 10 - owner: An object that calls this function. If the `takesOwner` property is true 11 and type of the first argument matches the owner type, it's being passed as the argument. 12 - args: An array of arguments to pass to the function. The arguments must be of the same type as in the underlying closure. 13 - Returns: A value returned by the called function when succeeded or an error when it failed. 14 */ 15 func call(by owner: AnyObject?, withArguments args: [Any]) throws -> Any 16 } 17 18 /** 19 Represents a function that can only be called synchronously. 20 */ 21 public final class SyncFunctionComponent<Args, FirstArgType, ReturnType>: AnySyncFunctionComponent { 22 typealias ClosureType = (Args) throws -> ReturnType 23 24 /** 25 The underlying closure to run when the function is called. 26 */ 27 let body: ClosureType 28 29 init( 30 _ name: String, 31 firstArgType: FirstArgType.Type, 32 dynamicArgumentTypes: [AnyDynamicType], 33 _ body: @escaping ClosureType 34 ) { 35 self.name = name 36 self.dynamicArgumentTypes = dynamicArgumentTypes 37 self.body = body 38 } 39 40 // MARK: - AnyFunction 41 42 let name: String 43 44 let dynamicArgumentTypes: [AnyDynamicType] 45 46 var argumentsCount: Int { 47 return dynamicArgumentTypes.count - (takesOwner ? 1 : 0) 48 } 49 50 var takesOwner: Bool = false 51 52 func call(by owner: AnyObject?, withArguments args: [Any], callback: @escaping (FunctionCallResult) -> ()) { 53 do { 54 let result = try call(by: owner, withArguments: args) 55 callback(.success(Conversions.convertFunctionResult(result))) 56 } catch let error as Exception { 57 callback(.failure(error)) 58 } catch { 59 callback(.failure(UnexpectedException(error))) 60 } 61 } 62 63 // MARK: - AnySyncFunctionComponent 64 65 func call(by owner: AnyObject?, withArguments args: [Any]) throws -> Any { 66 do { 67 let arguments = concat( 68 arguments: try cast(arguments: args, forFunction: self), 69 withOwner: owner, 70 forFunction: self 71 ) 72 let argumentsTuple = try Conversions.toTuple(arguments) as! Args 73 let result = try body(argumentsTuple) 74 return Conversions.convertFunctionResult(result) 75 } catch let error as Exception { 76 throw FunctionCallException(name).causedBy(error) 77 } catch { 78 throw UnexpectedException(error) 79 } 80 } 81 82 // MARK: - JavaScriptObjectBuilder 83 84 func build(inRuntime runtime: JavaScriptRuntime) -> JavaScriptObject { 85 return runtime.createSyncFunction(name, argsCount: argumentsCount) { [weak self, name] this, args in 86 guard let self = self else { 87 throw NativeFunctionUnavailableException(name) 88 } 89 let result = try self.call(by: this, withArguments: args) 90 return Conversions.convertFunctionResult(result) 91 } 92 } 93 } 94 95 /** 96 Synchronous function without arguments. 97 */ 98 public func Function<R>( 99 _ name: String, 100 @_implicitSelfCapture _ closure: @escaping () throws -> R 101 ) -> SyncFunctionComponent<(), Void, R> { 102 return SyncFunctionComponent( 103 name, 104 firstArgType: Void.self, 105 dynamicArgumentTypes: [], 106 closure 107 ) 108 } 109 110 /** 111 Synchronous function with one argument. 112 */ 113 public func Function<R, A0: AnyArgument>( 114 _ name: String, 115 @_implicitSelfCapture _ closure: @escaping (A0) throws -> R 116 ) -> SyncFunctionComponent<(A0), A0, R> { 117 return SyncFunctionComponent( 118 name, 119 firstArgType: A0.self, 120 dynamicArgumentTypes: [~A0.self], 121 closure 122 ) 123 } 124 125 /** 126 Synchronous function with two arguments. 127 */ 128 public func Function<R, A0: AnyArgument, A1: AnyArgument>( 129 _ name: String, 130 @_implicitSelfCapture _ closure: @escaping (A0, A1) throws -> R 131 ) -> SyncFunctionComponent<(A0, A1), A0, R> { 132 return SyncFunctionComponent( 133 name, 134 firstArgType: A0.self, 135 dynamicArgumentTypes: [~A0.self, ~A1.self], 136 closure 137 ) 138 } 139 140 /** 141 Synchronous function with three arguments. 142 */ 143 public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument>( 144 _ name: String, 145 @_implicitSelfCapture _ closure: @escaping (A0, A1, A2) throws -> R 146 ) -> SyncFunctionComponent<(A0, A1, A2), A0, R> { 147 return SyncFunctionComponent( 148 name, 149 firstArgType: A0.self, 150 dynamicArgumentTypes: [ 151 ~A0.self, 152 ~A1.self, 153 ~A2.self 154 ], 155 closure 156 ) 157 } 158 159 /** 160 Synchronous function with four arguments. 161 */ 162 public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument>( 163 _ name: String, 164 @_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3) throws -> R 165 ) -> SyncFunctionComponent<(A0, A1, A2, A3), A0, R> { 166 return SyncFunctionComponent( 167 name, 168 firstArgType: A0.self, 169 dynamicArgumentTypes: [ 170 ~A0.self, 171 ~A1.self, 172 ~A2.self, 173 ~A3.self 174 ], 175 closure 176 ) 177 } 178 179 /** 180 Synchronous function with five arguments. 181 */ 182 public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument>( 183 _ name: String, 184 @_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4) throws -> R 185 ) -> SyncFunctionComponent<(A0, A1, A2, A3, A4), A0, R> { 186 return SyncFunctionComponent( 187 name, 188 firstArgType: A0.self, 189 dynamicArgumentTypes: [ 190 ~A0.self, 191 ~A1.self, 192 ~A2.self, 193 ~A3.self, 194 ~A4.self 195 ], 196 closure 197 ) 198 } 199 200 /** 201 Synchronous function with six arguments. 202 */ 203 public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument>( 204 _ name: String, 205 @_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4, A5) throws -> R 206 ) -> SyncFunctionComponent<(A0, A1, A2, A3, A4, A5), A0, R> { 207 return SyncFunctionComponent( 208 name, 209 firstArgType: A0.self, 210 dynamicArgumentTypes: [ 211 ~A0.self, 212 ~A1.self, 213 ~A2.self, 214 ~A3.self, 215 ~A4.self, 216 ~A5.self 217 ], 218 closure 219 ) 220 } 221 222 /** 223 Synchronous function with seven arguments. 224 */ 225 public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument>( 226 _ name: String, 227 @_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4, A5, A6) throws -> R 228 ) -> SyncFunctionComponent<(A0, A1, A2, A3, A4, A5, A6), A0, R> { 229 return SyncFunctionComponent( 230 name, 231 firstArgType: A0.self, 232 dynamicArgumentTypes: [ 233 ~A0.self, 234 ~A1.self, 235 ~A2.self, 236 ~A3.self, 237 ~A4.self, 238 ~A5.self, 239 ~A6.self 240 ], 241 closure 242 ) 243 } 244 245 /** 246 Synchronous function with eight arguments. 247 */ 248 public func Function<R, A0: AnyArgument, A1: AnyArgument, A2: AnyArgument, A3: AnyArgument, A4: AnyArgument, A5: AnyArgument, A6: AnyArgument, A7: AnyArgument>( 249 _ name: String, 250 @_implicitSelfCapture _ closure: @escaping (A0, A1, A2, A3, A4, A5, A6, A7) throws -> R 251 ) -> SyncFunctionComponent<(A0, A1, A2, A3, A4, A5, A6, A7), A0, R> { 252 return SyncFunctionComponent( 253 name, 254 firstArgType: A0.self, 255 dynamicArgumentTypes: [ 256 ~A0.self, 257 ~A1.self, 258 ~A2.self, 259 ~A3.self, 260 ~A4.self, 261 ~A5.self, 262 ~A6.self, 263 ~A7.self 264 ], 265 closure 266 ) 267 } 268