Skip to content

Commit b04e85c

Browse files
committed
Initial Commit
1 parent b191a15 commit b04e85c

14 files changed

+957
-0
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/config/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc

Package.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// swift-tools-version: 5.7
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "WebWorkerKit",
6+
products: [
7+
.library(
8+
name: "WebWorkerKit",
9+
targets: ["WebWorkerKit"]),
10+
],
11+
dependencies: [
12+
.package(url: "https://github.com/swiftwasm/JavaScriptKit", from: "0.16.0"),
13+
],
14+
targets: [
15+
.target(
16+
name: "WebWorkerKit",
17+
dependencies: [
18+
"JavaScriptKit",
19+
.product(name: "JavaScriptEventLoop", package: "JavaScriptKit")
20+
]
21+
),
22+
.testTarget(
23+
name: "WebWorkerKitTests",
24+
dependencies: ["WebWorkerKit"]),
25+
]
26+
)

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# WebWorkerKit
2+
3+
A description of this package.
Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
import JavaScriptKit
2+
3+
private let ArrayConstructor = JSObject.global.Array.function!
4+
private let ObjectConstructor = JSObject.global.Object.function!
5+
6+
// TODO: Move this to JavaScriptKit
7+
public struct JSValueEncoder {
8+
public init() {}
9+
public func encode<T: Encodable>(_ value: T) throws -> JSValue {
10+
// Fast paths.
11+
// Without these, `Codable` will try to encode each value of the array
12+
// individually, which is orders of magnitudes slower.
13+
switch value {
14+
case let value as JSValue:
15+
return value
16+
case let value as [Double]:
17+
return JSTypedArray(value).jsValue
18+
case let value as [Float]:
19+
return JSTypedArray(value).jsValue
20+
case let value as [Int]:
21+
return JSTypedArray(value).jsValue
22+
case let value as [UInt]:
23+
return JSTypedArray(value).jsValue
24+
case let value as ConvertibleToJSValue:
25+
return value.jsValue
26+
default: break
27+
}
28+
29+
let encoder = JSValueEncoderImpl(codingPath: [])
30+
try value.encode(to: encoder)
31+
return encoder.value
32+
}
33+
}
34+
35+
private class JSValueEncoderImpl {
36+
let codingPath: [CodingKey]
37+
var value: JSValue = .undefined
38+
var userInfo: [CodingUserInfoKey : Any] = [:]
39+
40+
init(codingPath: [CodingKey]) {
41+
self.codingPath = codingPath
42+
}
43+
}
44+
45+
extension JSValueEncoderImpl: Encoder {
46+
func container<Key>(keyedBy _: Key.Type) -> KeyedEncodingContainer<Key> where Key: CodingKey {
47+
self.value = .object(ObjectConstructor.new())
48+
return KeyedEncodingContainer(JSObjectKeyedEncodingContainer<Key>(encoder: self))
49+
}
50+
51+
func singleValueContainer() -> SingleValueEncodingContainer {
52+
return SingleJSValueEncodingContainer(encoder: self)
53+
}
54+
55+
func unkeyedContainer() -> UnkeyedEncodingContainer {
56+
self.value = .object(ArrayConstructor.new())
57+
return JSUnkeyedEncodingContainer(encoder: self)
58+
}
59+
}
60+
61+
private struct JSObjectKeyedEncodingContainer<Key: CodingKey>: KeyedEncodingContainerProtocol {
62+
var codingPath: [CodingKey] {
63+
return encoder.codingPath
64+
}
65+
66+
let encoder: JSValueEncoderImpl
67+
init(encoder: JSValueEncoderImpl) {
68+
self.encoder = encoder
69+
}
70+
71+
func encodeNil(forKey key: Key) throws {
72+
encoder.value[dynamicMember: key.stringValue] = .null
73+
}
74+
75+
func encode(_ value: Bool, forKey key: Key) throws {
76+
encoder.value[dynamicMember: key.stringValue] = .boolean(value)
77+
}
78+
79+
func encode(_ value: String, forKey key: Key) throws {
80+
encoder.value[dynamicMember: key.stringValue] = .string(value)
81+
}
82+
83+
func encode(_ value: Double, forKey key: Key) throws {
84+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
85+
}
86+
87+
func encode(_ value: Float, forKey key: Key) throws {
88+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
89+
}
90+
91+
func encode(_ value: Int, forKey key: Key) throws {
92+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
93+
}
94+
95+
func encode(_ value: Int8, forKey key: Key) throws {
96+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
97+
}
98+
99+
func encode(_ value: Int16, forKey key: Key) throws {
100+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
101+
}
102+
103+
func encode(_ value: Int32, forKey key: Key) throws {
104+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
105+
}
106+
107+
func encode(_ value: Int64, forKey key: Key) throws {
108+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
109+
}
110+
111+
func encode(_ value: UInt, forKey key: Key) throws {
112+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
113+
}
114+
115+
func encode(_ value: UInt8, forKey key: Key) throws {
116+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
117+
}
118+
119+
func encode(_ value: UInt16, forKey key: Key) throws {
120+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
121+
}
122+
123+
func encode(_ value: UInt32, forKey key: Key) throws {
124+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
125+
}
126+
127+
func encode(_ value: UInt64, forKey key: Key) throws {
128+
encoder.value[dynamicMember: key.stringValue] = .number(Double(value))
129+
}
130+
131+
func encode<T>(_ value: T, forKey key: Key) throws where T : Encodable {
132+
encoder.value[dynamicMember: key.stringValue] = try JSValueEncoder().encode(value)
133+
}
134+
135+
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey
136+
{
137+
let encoder = JSValueEncoderImpl(codingPath: encoder.codingPath)
138+
let container = JSObjectKeyedEncodingContainer<NestedKey>(encoder: encoder)
139+
encoder.value = .object(ObjectConstructor.new())
140+
return KeyedEncodingContainer(container)
141+
}
142+
143+
func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {
144+
preconditionFailure("??")
145+
}
146+
147+
func superEncoder() -> Encoder {
148+
preconditionFailure("??")
149+
}
150+
151+
func superEncoder(forKey key: Key) -> Encoder {
152+
preconditionFailure("??")
153+
}
154+
}
155+
156+
private struct JSUnkeyedEncodingContainer: UnkeyedEncodingContainer {
157+
var codingPath: [CodingKey] { encoder.codingPath }
158+
159+
let encoder: JSValueEncoderImpl
160+
init(encoder: JSValueEncoderImpl) {
161+
self.encoder = encoder
162+
}
163+
164+
func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> where NestedKey : CodingKey
165+
{
166+
let encoder = JSValueEncoderImpl(codingPath: self.codingPath)
167+
return KeyedEncodingContainer(
168+
JSObjectKeyedEncodingContainer<NestedKey>(encoder: encoder)
169+
)
170+
}
171+
172+
func superEncoder() -> Encoder {
173+
preconditionFailure("??")
174+
}
175+
176+
func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {
177+
let newEncoder = JSValueEncoderImpl(codingPath: codingPath) // TODO add index to codingPath
178+
newEncoder.value = .object(ArrayConstructor.new())
179+
return JSUnkeyedEncodingContainer(encoder: newEncoder)
180+
}
181+
182+
var count: Int { Int(encoder.value.length.number!) }
183+
184+
func encodeNil() throws {
185+
_ = encoder.value.push(JSValue.null)
186+
}
187+
188+
func encode(_ value: Bool) throws {
189+
_ = encoder.value.push(JSValue.boolean(value))
190+
}
191+
192+
func encode(_ value: String) throws {
193+
_ = encoder.value.push(JSValue.string(value))
194+
}
195+
196+
func encode(_ value: Double) throws {
197+
_ = encoder.value.push(JSValue.number(Double(value)))
198+
}
199+
200+
func encode(_ value: Float) throws {
201+
_ = encoder.value.push(JSValue.number(Double(value)))
202+
}
203+
204+
func encode(_ value: Int) throws {
205+
_ = encoder.value.push(JSValue.number(Double(value)))
206+
}
207+
208+
func encode(_ value: Int8) throws {
209+
_ = encoder.value.push(JSValue.number(Double(value)))
210+
}
211+
212+
func encode(_ value: Int16) throws {
213+
_ = encoder.value.push(JSValue.number(Double(value)))
214+
}
215+
216+
func encode(_ value: Int32) throws {
217+
_ = encoder.value.push(JSValue.number(Double(value)))
218+
}
219+
220+
func encode(_ value: Int64) throws {
221+
_ = encoder.value.push(JSValue.number(Double(value)))
222+
}
223+
224+
func encode(_ value: UInt) throws {
225+
_ = encoder.value.push(JSValue.number(Double(value)))
226+
}
227+
228+
func encode(_ value: UInt8) throws {
229+
_ = encoder.value.push(JSValue.number(Double(value)))
230+
}
231+
232+
func encode(_ value: UInt16) throws {
233+
_ = encoder.value.push(JSValue.number(Double(value)))
234+
}
235+
236+
func encode(_ value: UInt32) throws {
237+
_ = encoder.value.push(JSValue.number(Double(value)))
238+
}
239+
240+
func encode(_ value: UInt64) throws {
241+
_ = encoder.value.push(JSValue.number(Double(value)))
242+
}
243+
244+
func encode<T>(_ value: T) throws where T: Encodable {
245+
let newEncoder = JSValueEncoderImpl(codingPath: []) // TODO: coding path?
246+
try value.encode(to: newEncoder)
247+
_ = encoder.value.push(newEncoder.value)
248+
}
249+
}
250+
251+
private struct SingleJSValueEncodingContainer: SingleValueEncodingContainer {
252+
var codingPath: [CodingKey] { encoder.codingPath }
253+
let encoder: JSValueEncoderImpl
254+
init(encoder: JSValueEncoderImpl) {
255+
self.encoder = encoder
256+
}
257+
258+
func encode<T>(_ value: T) throws where T: Encodable {
259+
encoder.value = try JSValueEncoder().encode(value)
260+
}
261+
262+
public func encode(_ value: Bool) throws {
263+
encoder.value = .boolean(value)
264+
}
265+
266+
public func encode(_ value: String) throws {
267+
encoder.value = .string(value)
268+
}
269+
270+
public func encode(_ value: Double) throws {
271+
encoder.value = .number(value)
272+
}
273+
274+
public func encode(_ value: Float) throws {
275+
encoder.value = .number(Double(value))
276+
}
277+
278+
public func encode(_ value: Int) throws {
279+
encoder.value = .number(Double(value))
280+
}
281+
282+
public func encode(_ value: Int8) throws {
283+
encoder.value = .number(Double(value))
284+
}
285+
286+
public func encode(_ value: Int16) throws {
287+
encoder.value = .number(Double(value))
288+
}
289+
290+
public func encode(_ value: Int32) throws {
291+
encoder.value = .number(Double(value))
292+
}
293+
294+
public func encode(_ value: Int64) throws {
295+
encoder.value = .number(Double(value))
296+
}
297+
298+
public func encode(_ value: UInt) throws {
299+
encoder.value = .number(Double(value))
300+
}
301+
302+
public func encode(_ value: UInt8) throws {
303+
encoder.value = .number(Double(value))
304+
}
305+
306+
public func encode(_ value: UInt16) throws {
307+
encoder.value = .number(Double(value))
308+
}
309+
310+
public func encode(_ value: UInt32) throws {
311+
encoder.value = .number(Double(value))
312+
}
313+
314+
public func encode(_ value: UInt64) throws {
315+
encoder.value = .number(Double(value))
316+
}
317+
318+
public func encodeNil() throws {
319+
encoder.value = .null
320+
}
321+
}

Sources/WebWorkerKit/WebWorker.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import JavaScriptKit
2+
import Distributed
3+
4+
public protocol WebWorker: DistributedActor where ActorSystem == WebWorkerActorSystem, Self: Hashable {
5+
init(actorSystem: ActorSystem)
6+
7+
/// Set a custom URL to initialize the web worker instance by.
8+
/// Defaults to the scriptPath the host (main thread) was loaded in.
9+
static var scriptPath: String? { get }
10+
11+
/// Whether to load the worker script defined by `scriptPath` as an es-module
12+
static var isModule: Bool { get }
13+
}
14+
15+
extension DistributedActor where ActorSystem == WebWorkerActorSystem {
16+
public static func new() throws -> Self {
17+
return try! Self.resolve(
18+
id: .singleton(for: Self.self),
19+
using: .shared
20+
)
21+
}
22+
}

0 commit comments

Comments
 (0)