// Copyright 2025-present 650 Industries. All rights reserved. import Foundation // `Data` converts to and from a JavaScript `Uint8Array`. Decoding copies the typed array's bytes // into `Data`; encoding copies the bytes into a new `ArrayBuffer` wrapped in a `Uint8Array`. // // `Data` is not in `+Primitives` because it is not a scalar. It maps to a typed array, with its own // read/write rather than a single accessor. extension Data: JavaScriptCodable { @JavaScriptActor @inlinable public static func decode(_ value: borrowing JavaScriptValue, in runtime: borrowing JavaScriptRuntime) throws -> Data { guard value.isTypedArray() else { throw DataNotUint8ArrayException() } let typedArray = value.getTypedArray() guard typedArray.kind == .Uint8Array else { throw DataNotUint8ArrayException() } return typedArray.withUnsafeBytes { bytes in guard typedArray.byteLength > 0, let baseAddress = bytes.baseAddress else { return Data() } return Data(bytes: baseAddress, count: typedArray.byteLength) } } @JavaScriptActor @inlinable public static func encode(_ value: Data, in runtime: borrowing JavaScriptRuntime) throws -> JavaScriptValue { let arrayBuffer = runtime.createArrayBuffer(size: value.count) value.withUnsafeBytes { rawBuffer in if let baseAddress = rawBuffer.baseAddress, value.count > 0 { memcpy(arrayBuffer.data(), baseAddress, value.count) } } let uint8ArrayConstructor = try runtime.global().getPropertyAsFunction("Uint8Array") return try uint8ArrayConstructor.callAsConstructor(arrayBuffer.asValue()) } } /// Thrown when decoding `Data` from a JavaScript value that is not a `Uint8Array`. public struct DataNotUint8ArrayException: JavaScriptThrowable { @usableFromInline init() {} public var code: String { "ERR_DATA_NOT_UINT8ARRAY" } public var message: String { "Cannot convert a JavaScript value to Data because it is not a Uint8Array" } }