From: Lady Date: Mon, 26 Jun 2023 01:57:06 +0000 (-0700) Subject: Support SharedArrayBuffer; drop isDataView X-Git-Tag: 0.4.0~2 X-Git-Url: https://git.ladys.computer/Pisces/commitdiff_plain/dc0583fa3a21dff2e276b012dbb910eb1165000f Support SharedArrayBuffer; drop isDataView - `SharedArrayBuffer` counts as an array buffer; use `isArrayBuffer($) && !isSharedArrayBuffer($)` to detect only non‐shared buffers. - `isDataView` is no longer supported as a separate function; use `isArrayBufferView($) && !isTypedArray($)` to detect data views. --- diff --git a/binary.js b/binary.js index f6d8cab..aac9975 100644 --- a/binary.js +++ b/binary.js @@ -24,6 +24,7 @@ const View = DataView; const TypedArray = Object.getPrototypeOf(Uint8Array); const { prototype: arrayPrototype } = Array; const { prototype: bufferPrototype } = Buffer; +const { prototype: sharedBufferPrototype } = SharedArrayBuffer; const { prototype: rePrototype } = RegExp; const { prototype: typedArrayPrototype } = TypedArray; const { prototype: viewPrototype } = View; @@ -58,10 +59,23 @@ const binaryCodeUnitIterablePrototype = { const { exec: reExec } = rePrototype; const getBufferByteLength = Object.getOwnPropertyDescriptor(bufferPrototype, "byteLength").get; +const getSharedBufferByteLength = + Object.getOwnPropertyDescriptor(sharedBufferPrototype, "byteLength") + .get; const getTypedArrayBuffer = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get; +const getTypedArrayByteLength = + Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength") + .get; +const getTypedArrayByteOffset = + Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset") + .get; const getViewBuffer = Object.getOwnPropertyDescriptor(viewPrototype, "buffer").get; +const getViewByteLength = + Object.getOwnPropertyDescriptor(viewPrototype, "byteLength").get; +const getViewByteOffset = + Object.getOwnPropertyDescriptor(viewPrototype, "byteOffset").get; const { getUint8: viewGetUint8, setUint8: viewSetUint8, @@ -646,6 +660,83 @@ export const filenameSafeBase64Binary = ($, ...$s) => export const filenameSafeBase64String = ($, ...$s) => encodeBase64(bufferFromArgs($, $s), true); +/** + * Returns the byte length for the provided array buffer or array + * buffer view. + * + * ☡ This function throws if the provided value is not an array buffer, + * data view, or typed array. + */ +export const getByteLength = ($) => { + try { + // Attempt to get the byte length from the provided value as an + // `ArrayBuffer`. + return call(getBufferByteLength, $, []); + } catch { + // The provided value is not an `ArrayBuffer`. + /* do nothing */ + } + try { + // Attempt to get the byte length from the provided value as a + // `SharedArrayBuffer`. + return call(getSharedBufferByteLength, $, []); + } catch { + // The provided value is not a `SharedArrayBuffer`. + /* do nothing */ + } + try { + // Attempt to get the byte length from the provided value as a + // data view. + return call(getViewByteLength, $, []); + } catch { + // The provided value is not a data view. + /* do nothing */ + } + try { + // Attempt to get the byte length from the provided value as a + // typed array. + return call(getTypedArrayByteLength, $, []); + } catch { + // The provided value is not a typed array. + /* do nothing */ + } + throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`); +}; + +/** + * Returns the byte offset for the provided array buffer or array + * buffer view. + * + * ※ This function always returns `0` for array buffers. + * + * ☡ This function throws if the provided value is not an array buffer, + * data view, or typed array. + */ +export const getByteOffset = ($) => { + if (isArrayBuffer($)) { + // The provided value is an array buffer. + return 0; + } else { + try { + // Attempt to get the byte offset from the provided value as a + // data view. + return call(getViewByteOffset, $, []); + } catch { + // The provided value is not a data view. + /* do nothing */ + } + try { + // Attempt to get the byte offset from the provided value as a + // typed array. + return call(getTypedArrayByteOffset, $, []); + } catch { + // The provided value is not a typed array. + /* do nothing */ + } + throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`); + } +}; + /** * Returns whether the provided value is a view on an underlying array * buffer. @@ -654,7 +745,12 @@ export const filenameSafeBase64String = ($, ...$s) => */ export const { isView: isArrayBufferView } = Buffer; -/** Returns whether the provided value is an array buffer. */ +/** + * Returns whether the provided value is an array buffer. + * + * ※ This function returns true for both `ArrayBuffer`s and + * `SharedArrayBuffer`s. + */ export const isArrayBuffer = ($) => { try { // Try to see if the provided argument has array buffer internal @@ -664,6 +760,14 @@ export const isArrayBuffer = ($) => { // The provided argument does not have array buffer internal slots. /* do nothing */ } + try { + // Try to see if the provided argument has array buffer internal + // slots and return true if so. + return call(getSharedBufferByteLength, $, []), true; + } catch { + // The provided argument does not have array buffer internal slots. + /* do nothing */ + } return false; }; @@ -727,18 +831,6 @@ export const isBase64 = ($) => { } }; -/** Returns whether the provided value is a data view. */ -export const isDataView = ($) => { - try { - // Try to see if the provided argument has data view internal slots - // and return true if so. - return call(getViewBuffer, $, []), true; - } catch { - // The provided argument does not have data view internal slots. - return false; - } -}; - /** * Returns whether the provided value is a filename‐safe base64 string. * @@ -760,6 +852,18 @@ export const isFilenameSafeBase64 = ($) => { } }; +/** Returns whether the provided value is a shared array buffer. */ +export const isSharedArrayBuffer = ($) => { + try { + // Try to see if the provided argument has shared array buffer + // internal slots and return true if so. + return call(getSharedBufferByteLength, $, []), true; + } catch { + // The provided argument does not have data view internal slots. + return false; + } +}; + /** Returns whether the provided value is a typed array. */ export const isTypedArray = ($) => { try { diff --git a/binary.test.js b/binary.test.js index 9d8c169..00860ed 100644 --- a/binary.test.js +++ b/binary.test.js @@ -29,8 +29,8 @@ import { isBase16, isBase32, isBase64, - isDataView, isFilenameSafeBase64, + isSharedArrayBuffer, isTypedArray, isWRMGBase32, toArrayBuffer, @@ -589,6 +589,10 @@ describe("isArrayBuffer", () => { isArrayBuffer(new ArrayBuffer()), true, ); + assertStrictEquals( + isArrayBuffer(new SharedArrayBuffer()), + true, + ); }); it("[[Call]] returns false for others", () => { @@ -604,7 +608,6 @@ describe("isArrayBuffer", () => { () => {}, new Proxy({}, {}), "string", - new SharedArrayBuffer(), new DataView(new ArrayBuffer()), new Uint8Array(), ].forEach((value) => @@ -731,12 +734,16 @@ describe("isBase64", () => { }); }); -describe("isDataView", () => { - it("[[Call]] returns true for data views", () => { - assertStrictEquals( - isDataView(new DataView(new ArrayBuffer())), - true, - ); +describe("isFilenameSafeBase64", () => { + it("[[Call]] returns true for filename‐safe base64 strings", () => { + for (const { base64 } of data.values()) { + assertStrictEquals( + isFilenameSafeBase64( + base64.replace("+", "-").replace("/", "_"), + ), + true, + ); + } }); it("[[Call]] returns false for others", () => { @@ -751,24 +758,21 @@ describe("isDataView", () => { [], () => {}, new Proxy({}, {}), - "string", - new ArrayBuffer(), - new SharedArrayBuffer(), - new Uint8Array(), - ].forEach((value) => assertStrictEquals(isDataView(value), false)); + "abc/", + "a", + "abc==", + ].forEach((value) => + assertStrictEquals(isFilenameSafeBase64(value), false) + ); }); }); -describe("isFilenameSafeBase64", () => { - it("[[Call]] returns true for filename‐safe base64 strings", () => { - for (const { base64 } of data.values()) { - assertStrictEquals( - isFilenameSafeBase64( - base64.replace("+", "-").replace("/", "_"), - ), - true, - ); - } +describe("isSharedArrayBuffer", () => { + it("[[Call]] returns true for shared array buffers", () => { + assertStrictEquals( + isSharedArrayBuffer(new SharedArrayBuffer()), + true, + ); }); it("[[Call]] returns false for others", () => { @@ -783,11 +787,12 @@ describe("isFilenameSafeBase64", () => { [], () => {}, new Proxy({}, {}), - "abc/", - "a", - "abc==", + "string", + new ArrayBuffer(), + new DataView(new ArrayBuffer()), + new Uint8Array(), ].forEach((value) => - assertStrictEquals(isFilenameSafeBase64(value), false) + assertStrictEquals(isSharedArrayBuffer(value), false) ); }); });