Skip to content

Commit c0ddc7d

Browse files
Merge pull request #315 from swiftwasm/yt/add-copy-memory
Add `JSTypedArray.copyMemory(to:)` method
2 parents 620365b + 2e7aa2f commit c0ddc7d

File tree

2 files changed

+36
-24
lines changed

2 files changed

+36
-24
lines changed

Sources/JavaScriptKit/BasicObjects/JSTypedArray.swift

+22-24
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral wh
7979
Int(jsObject["byteLength"].number!)
8080
}
8181

82+
/// Length (in elements) of the typed array.
83+
public var length: Int {
84+
Int(jsObject["length"].number!)
85+
}
86+
8287
/// Calls the given closure with a pointer to a copy of the underlying bytes of the
8388
/// array's storage.
8489
///
@@ -93,18 +98,10 @@ public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral wh
9398
/// argument is valid only for the duration of the closure's execution.
9499
/// - Returns: The return value, if any, of the `body` closure parameter.
95100
public func withUnsafeBytes<R>(_ body: (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R {
96-
let bytesLength = lengthInBytes
97-
let rawBuffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: bytesLength)
98-
defer { rawBuffer.deallocate() }
99-
let baseAddress = rawBuffer.baseAddress!
100-
swjs_load_typed_array(jsObject.id, baseAddress)
101-
let length = bytesLength / MemoryLayout<Element>.size
102-
let rawBaseAddress = UnsafeRawPointer(baseAddress)
103-
let bufferPtr = UnsafeBufferPointer<Element>(
104-
start: rawBaseAddress.assumingMemoryBound(to: Element.self),
105-
count: length
106-
)
107-
let result = try body(bufferPtr)
101+
let buffer = UnsafeMutableBufferPointer<Element>.allocate(capacity: length)
102+
defer { buffer.deallocate() }
103+
copyMemory(to: buffer)
104+
let result = try body(UnsafeBufferPointer(buffer))
108105
return result
109106
}
110107

@@ -124,21 +121,22 @@ public class JSTypedArray<Element>: JSBridgedClass, ExpressibleByArrayLiteral wh
124121
/// - Returns: The return value, if any, of the `body`async closure parameter.
125122
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
126123
public func withUnsafeBytesAsync<R>(_ body: (UnsafeBufferPointer<Element>) async throws -> R) async rethrows -> R {
127-
let bytesLength = lengthInBytes
128-
let rawBuffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: bytesLength)
129-
defer { rawBuffer.deallocate() }
130-
let baseAddress = rawBuffer.baseAddress!
131-
swjs_load_typed_array(jsObject.id, baseAddress)
132-
let length = bytesLength / MemoryLayout<Element>.size
133-
let rawBaseAddress = UnsafeRawPointer(baseAddress)
134-
let bufferPtr = UnsafeBufferPointer<Element>(
135-
start: rawBaseAddress.assumingMemoryBound(to: Element.self),
136-
count: length
137-
)
138-
let result = try await body(bufferPtr)
124+
let buffer = UnsafeMutableBufferPointer<Element>.allocate(capacity: length)
125+
defer { buffer.deallocate() }
126+
copyMemory(to: buffer)
127+
let result = try await body(UnsafeBufferPointer(buffer))
139128
return result
140129
}
141130
#endif
131+
132+
/// Copies the contents of the array to the given buffer.
133+
///
134+
/// - Parameter buffer: The buffer to copy the contents of the array to.
135+
/// The buffer must have enough space to accommodate the contents of the array.
136+
public func copyMemory(to buffer: UnsafeMutableBufferPointer<Element>) {
137+
precondition(buffer.count >= length, "Buffer is too small to hold the contents of the array")
138+
swjs_load_typed_array(jsObject.id, buffer.baseAddress!)
139+
}
142140
}
143141

144142
// MARK: - Int and UInt support

Tests/JavaScriptKitTests/JSTypedArrayTests.swift

+14
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,18 @@ final class JSTypedArrayTests: XCTestCase {
109109
XCTAssertEqual(typedArray[i], Float32(i))
110110
}
111111
}
112+
113+
func testCopyMemory() {
114+
let array = JSTypedArray<Int>(length: 100)
115+
for i in 0..<100 {
116+
array[i] = i
117+
}
118+
let destination = UnsafeMutableBufferPointer<Int>.allocate(capacity: 100)
119+
defer { destination.deallocate() }
120+
array.copyMemory(to: destination)
121+
122+
for i in 0..<100 {
123+
XCTAssertEqual(destination[i], i)
124+
}
125+
}
112126
}

0 commit comments

Comments
 (0)