Skip to content

Commit 2962215

Browse files
committed
Add a helper method to copy an array of numbers to a JS TypedArray
1 parent 19365a1 commit 2962215

File tree

6 files changed

+142
-0
lines changed

6 files changed

+142
-0
lines changed

IntegrationTests/TestSuites/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

IntegrationTests/TestSuites/Sources/PrimaryTests/main.swift

+7
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,10 @@ ObjectRef_Lifetime: do {
334334
} catch {
335335
print(error)
336336
}
337+
338+
TypedArray: do {
339+
let numbers = [UInt8](0 ... 255)
340+
let typedArray = JSObjectRef.createTypedArray(numbers)
341+
try expectEqual(typedArray[12], .number(12))
342+
try expectEqual(typedArray.toString!(), .string(numbers.map(String.init).joined(separator: ",")))
343+
}

Runtime/src/index.ts

+36
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,32 @@ enum JavaScriptValueKind {
3131
Function = 6,
3232
}
3333

34+
enum JavaScriptTypedArrayKind {
35+
Int8 = 0,
36+
Uint8 = 1,
37+
Int16 = 2,
38+
Uint16 = 3,
39+
Int32 = 4,
40+
Uint32 = 5,
41+
BigInt64 = 6,
42+
BigUint64 = 7,
43+
Float32 = 8,
44+
Float64 = 9,
45+
}
46+
47+
type TypedArray =
48+
| Int8ArrayConstructor
49+
| Uint8ArrayConstructor
50+
| Int16ArrayConstructor
51+
| Uint16ArrayConstructor
52+
| Int32ArrayConstructor
53+
| Uint32ArrayConstructor
54+
// | BigInt64ArrayConstructor
55+
// | BigUint64ArrayConstructor
56+
| Float32ArrayConstructor
57+
| Float64ArrayConstructor
58+
59+
3460
type SwiftRuntimeHeapEntry = {
3561
id: number,
3662
rc: number,
@@ -370,6 +396,16 @@ export class SwiftRuntime {
370396
const constructor = this.heap.referenceHeap(constructor_ref)
371397
return obj instanceof constructor
372398
},
399+
swjs_copy_typed_array_content: (
400+
kind: JavaScriptTypedArrayKind,
401+
elementsPtr: pointer, length: number,
402+
result_obj: pointer
403+
) => {
404+
const ArrayType: TypedArray = this.heap.referenceHeap(0)[JavaScriptTypedArrayKind[kind] + 'Array']
405+
const array = new ArrayType(memory().buffer, elementsPtr, length);
406+
// Call `.slice()` to copy the memory
407+
writeUint32(result_obj, this.heap.allocHeap(array.slice()));
408+
},
373409
swjs_destroy_ref: (ref: ref) => {
374410
this.heap.freeHeap(ref)
375411
}

Sources/JavaScriptKit/JSObject.swift

+63
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,67 @@ public class JSObjectRef: Equatable {
5757
public func jsValue() -> JSValue {
5858
.object(self)
5959
}
60+
61+
public class func createTypedArray<Type>(_ array: [Type]) -> JSObjectRef where Type: TypedArrayElement {
62+
let type: JavaScriptTypedArrayKind
63+
switch Type.self {
64+
case is Int8.Type:
65+
type = .int8
66+
case is UInt8.Type:
67+
type = .uint8
68+
case is Int16.Type:
69+
type = .int16
70+
case is UInt16.Type:
71+
type = .uint16
72+
case is Int32.Type:
73+
type = .int32
74+
case is UInt32.Type:
75+
type = .uint32
76+
case is Int64.Type:
77+
type = .bigInt64
78+
case is UInt64.Type:
79+
type = .bigUint64
80+
case is Float32.Type:
81+
type = .float32
82+
case is Float64.Type:
83+
type = .float64
84+
default:
85+
if Type.self is UInt.Type || Type.self is Int.Type {
86+
if UInt.bitWidth == 32 {
87+
if Type.self is UInt.Type {
88+
type = .uint32
89+
} else {
90+
type = .int32
91+
}
92+
} else if UInt.bitWidth == 64 {
93+
if Type.self is UInt.Type {
94+
type = .bigUint64
95+
} else {
96+
type = .bigInt64
97+
}
98+
} else {
99+
fatalError("Unsupported bit width type for UInt: \(UInt.bitWidth) (hint: stick to fixed-size ints to avoid this issue)")
100+
}
101+
} else {
102+
fatalError("Unsupported Swift type for TypedArray: \(Type.self)")
103+
}
104+
}
105+
var resultObj = JavaScriptObjectRef()
106+
array.withUnsafeBufferPointer { ptr in
107+
_copy_typed_array_content(type, ptr.baseAddress!, Int32(array.count), &resultObj)
108+
}
109+
return JSObjectRef(id: resultObj)
110+
}
60111
}
112+
113+
public protocol TypedArrayElement {}
114+
extension Int8: TypedArrayElement {}
115+
extension UInt8: TypedArrayElement {}
116+
extension Int16: TypedArrayElement {}
117+
extension UInt16: TypedArrayElement {}
118+
extension Int32: TypedArrayElement {}
119+
extension UInt32: TypedArrayElement {}
120+
extension Int64: TypedArrayElement {}
121+
extension UInt64: TypedArrayElement {}
122+
extension Float32: TypedArrayElement {}
123+
extension Float64: TypedArrayElement {}

Sources/JavaScriptKit/XcodeSupport.swift

+7
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,11 @@ import _CJavaScriptKit
7373
_: UnsafePointer<JavaScriptObjectRef>!
7474
) { fatalError() }
7575
func _destroy_ref(_: JavaScriptObjectRef) { fatalError() }
76+
func _copy_typed_array_content<T: TypedArrayElement>(
77+
_: JavaScriptTypedArrayKind,
78+
_: UnsafePointer<T>,
79+
_: Int32,
80+
_: UnsafeMutablePointer<JavaScriptObjectRef>!
81+
) { fatalError() }
82+
7683
#endif

Sources/_CJavaScriptKit/include/_CJavaScriptKit.h

+22
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ typedef enum __attribute__((enum_extensibility(closed))) {
1818
JavaScriptValueKindFunction = 6,
1919
} JavaScriptValueKind;
2020

21+
typedef enum __attribute__((enum_extensibility(closed))) {
22+
JavaScriptTypedArrayKindInt8 = 0,
23+
JavaScriptTypedArrayKindUint8 = 1,
24+
JavaScriptTypedArrayKindInt16 = 2,
25+
JavaScriptTypedArrayKindUint16 = 3,
26+
JavaScriptTypedArrayKindInt32 = 4,
27+
JavaScriptTypedArrayKindUint32 = 5,
28+
JavaScriptTypedArrayKindBigInt64 = 6,
29+
JavaScriptTypedArrayKindBigUint64 = 7,
30+
JavaScriptTypedArrayKindFloat32 = 8,
31+
JavaScriptTypedArrayKindFloat64 = 9,
32+
} JavaScriptTypedArrayKind;
33+
34+
2135
typedef unsigned JavaScriptPayload1;
2236
typedef unsigned JavaScriptPayload2;
2337
typedef double JavaScriptPayload3;
@@ -97,6 +111,14 @@ __attribute__((__import_module__("javascript_kit"),
97111
__import_name__("swjs_destroy_ref"))) extern void
98112
_destroy_ref(const JavaScriptObjectRef ref);
99113

114+
__attribute__((
115+
__import_module__("javascript_kit"),
116+
__import_name__("swjs_copy_typed_array_content")
117+
))
118+
extern void _copy_typed_array_content(const JavaScriptTypedArrayKind kind,
119+
const void *elementsPtr, const int length,
120+
JavaScriptObjectRef *result_obj);
121+
100122
#endif
101123

102124
#endif /* _CJavaScriptKit_h */

0 commit comments

Comments
 (0)