diff --git a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift index 19602a31..b9d8d520 100644 --- a/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift +++ b/Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift @@ -46,13 +46,10 @@ public class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiteral wh /// /// - Parameter array: The array that will be copied to create a new instance of TypedArray public convenience init(_ array: [Element]) { - let jsArrayRef = array.withUnsafeBufferPointer { ptr in - // Retain the constructor function to avoid it being released before calling `swjs_create_typed_array` - withExtendedLifetime(Self.constructor!) { ctor in - swjs_create_typed_array(ctor.id, ptr.baseAddress, Int32(array.count)) - } + let object = array.withUnsafeBufferPointer { buffer in + Self.createTypedArray(from: buffer) } - self.init(unsafelyWrapping: JSObject(id: jsArrayRef)) + self.init(unsafelyWrapping: object) } /// Convenience initializer for `Sequence`. @@ -60,6 +57,21 @@ public class JSTypedArray: JSBridgedClass, ExpressibleByArrayLiteral wh self.init(Array(sequence)) } + /// Initialize a new instance of TypedArray in JavaScript environment with given buffer contents. + /// + /// - Parameter buffer: The buffer that will be copied to create a new instance of TypedArray + public convenience init(buffer: UnsafeBufferPointer) { + self.init(unsafelyWrapping: Self.createTypedArray(from: buffer)) + } + + private static func createTypedArray(from buffer: UnsafeBufferPointer) -> JSObject { + // Retain the constructor function to avoid it being released before calling `swjs_create_typed_array` + let jsArrayRef = withExtendedLifetime(Self.constructor!) { ctor in + swjs_create_typed_array(ctor.id, buffer.baseAddress, Int32(buffer.count)) + } + return JSObject(id: jsArrayRef) + } + /// Length (in bytes) of the typed array. /// The value is established when a TypedArray is constructed and cannot be changed. /// If the TypedArray is not specifying a `byteOffset` or a `length`, the `length` of the referenced `ArrayBuffer` will be returned. diff --git a/Tests/JavaScriptKitTests/JSTypedArrayTests.swift b/Tests/JavaScriptKitTests/JSTypedArrayTests.swift index 8e2556f8..dcc5fb26 100644 --- a/Tests/JavaScriptKitTests/JSTypedArrayTests.swift +++ b/Tests/JavaScriptKitTests/JSTypedArrayTests.swift @@ -97,4 +97,16 @@ final class JSTypedArrayTests: XCTestCase { XCTAssertEqual(toString(array.jsValue.object!), jsStringify(Array(0..<100))) } + + func testInitWithBufferPointer() { + let buffer = UnsafeMutableBufferPointer.allocate(capacity: 20) + defer { buffer.deallocate() } + for i in 0..<20 { + buffer[i] = Float32(i) + } + let typedArray = JSTypedArray(buffer: UnsafeBufferPointer(buffer)) + for i in 0..<20 { + XCTAssertEqual(typedArray[i], Float32(i)) + } + } }