Skip to content

Commit 304116e

Browse files
Add JavaScriptFoundationCompat module to provide utilities to interact Foundation types
1 parent 233d6b2 commit 304116e

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

Package.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,18 @@ let package = Package(
106106
"JavaScriptEventLoopTestSupport",
107107
]
108108
),
109+
.target(
110+
name: "JavaScriptFoundationCompat",
111+
dependencies: [
112+
"JavaScriptKit"
113+
]
114+
),
115+
.testTarget(
116+
name: "JavaScriptFoundationCompatTests",
117+
dependencies: [
118+
"JavaScriptFoundationCompat"
119+
]
120+
),
109121
.plugin(
110122
name: "PackageToJS",
111123
capability: .command(
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Foundation
2+
import JavaScriptKit
3+
4+
/// Data <-> Uint8Array conversion. The conversion is lossless and copies the bytes at most once per conversion
5+
extension Data: ConvertibleToJSValue, ConstructibleFromJSValue {
6+
/// Convert a Data to a JSValue.
7+
///
8+
/// - Returns: A Uint8Array that contains the bytes of the Data.
9+
public var jsValue: JSValue {
10+
self.withUnsafeBytes { buffer in
11+
return JSTypedArray<UInt8>(buffer: buffer.bindMemory(to: UInt8.self)).jsValue
12+
}
13+
}
14+
15+
/// Construct a Data from a JSValue.
16+
///
17+
/// - Parameter jsValue: The JSValue to construct a Data from.
18+
/// - Returns: A Data, if the JSValue is a Uint8Array.
19+
public static func construct(from jsValue: JSValue) -> Data? {
20+
guard let uint8Array = JSTypedArray<UInt8>(from: jsValue) else {
21+
// If the JSValue is not a Uint8Array, fail.
22+
return nil
23+
}
24+
// First, allocate the data storage
25+
var data = Data(count: uint8Array.lengthInBytes)
26+
// Then, copy the byte contents into the Data buffer
27+
data.withUnsafeMutableBytes { destinationBuffer in
28+
uint8Array.copyMemory(to: destinationBuffer.bindMemory(to: UInt8.self))
29+
}
30+
return data
31+
}
32+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import XCTest
2+
import Foundation
3+
import JavaScriptFoundationCompat
4+
import JavaScriptKit
5+
6+
final class DataJSValueTests: XCTestCase {
7+
func testDataToJSValue() {
8+
let data = Data([0x00, 0x01, 0x02, 0x03])
9+
let jsValue = data.jsValue
10+
11+
let uint8Array = JSTypedArray<UInt8>(from: jsValue)
12+
XCTAssertEqual(uint8Array?.lengthInBytes, 4)
13+
XCTAssertEqual(uint8Array?[0], 0x00)
14+
XCTAssertEqual(uint8Array?[1], 0x01)
15+
XCTAssertEqual(uint8Array?[2], 0x02)
16+
XCTAssertEqual(uint8Array?[3], 0x03)
17+
}
18+
19+
func testJSValueToData() {
20+
let jsValue = JSTypedArray<UInt8>([0x00, 0x01, 0x02, 0x03]).jsValue
21+
let data = Data.construct(from: jsValue)
22+
XCTAssertEqual(data, Data([0x00, 0x01, 0x02, 0x03]))
23+
}
24+
25+
func testDataToJSValue_withLargeData() {
26+
let data = Data(repeating: 0x00, count: 1024 * 1024)
27+
let jsValue = data.jsValue
28+
let uint8Array = JSTypedArray<UInt8>(from: jsValue)
29+
XCTAssertEqual(uint8Array?.lengthInBytes, 1024 * 1024)
30+
}
31+
32+
func testJSValueToData_withLargeData() {
33+
let jsValue = JSTypedArray<UInt8>(Array(repeating: 0x00, count: 1024 * 1024)).jsValue
34+
let data = Data.construct(from: jsValue)
35+
XCTAssertEqual(data?.count, 1024 * 1024)
36+
}
37+
38+
func testDataToJSValue_withEmptyData() {
39+
let data = Data()
40+
let jsValue = data.jsValue
41+
let uint8Array = JSTypedArray<UInt8>(from: jsValue)
42+
XCTAssertEqual(uint8Array?.lengthInBytes, 0)
43+
}
44+
45+
func testJSValueToData_withEmptyData() {
46+
let jsValue = JSTypedArray<UInt8>([]).jsValue
47+
let data = Data.construct(from: jsValue)
48+
XCTAssertEqual(data, Data())
49+
}
50+
51+
func testJSValueToData_withInvalidJSValue() {
52+
let data = Data.construct(from: JSObject().jsValue)
53+
XCTAssertNil(data)
54+
}
55+
}

0 commit comments

Comments
 (0)