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