1 // ♓🌟 Piscēs ∷ binary.js
2 // ====================================================================
4 // Copyright © 2020–2023 Lady [@ Lady’s Computer].
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
10 import { fill
, map
, reduce
} from "./collection.js";
11 import { bind
, call
} from "./function.js";
12 import { ceil
, floor
} from "./numeric.js";
13 import { hasOwnProperty
, objectCreate
} from "./object.js";
20 import { ITERATOR
} from "./value.js";
22 const Buffer
= ArrayBuffer
;
23 const View
= DataView
;
24 const TypedArray
= Object
.getPrototypeOf(Uint8Array
);
25 const { prototype: arrayPrototype
} = Array
;
26 const { prototype: bufferPrototype
} = Buffer
;
27 const { prototype: sharedBufferPrototype
} = SharedArrayBuffer
;
28 const { prototype: rePrototype
} = RegExp
;
29 const { prototype: typedArrayPrototype
} = TypedArray
;
30 const { prototype: viewPrototype
} = View
;
32 const { [ITERATOR
]: arrayIterator
} = arrayPrototype
;
34 next
: arrayIteratorNext
,
35 } = Object
.getPrototypeOf([][ITERATOR
]());
36 const argumentIterablePrototype
= {
41 call(arrayIterator
, this.args
, []),
47 const binaryCodeUnitIterablePrototype
= {
52 call(arrayIterator
, this, []),
59 const { exec
: reExec
} = rePrototype
;
60 const { slice
: bufferSlice
} = bufferPrototype
;
61 const getBufferByteLength
=
62 Object
.getOwnPropertyDescriptor(bufferPrototype
, "byteLength").get;
63 const { slice
: sharedBufferSlice
} = sharedBufferPrototype
;
64 const getSharedBufferByteLength
=
65 Object
.getOwnPropertyDescriptor(sharedBufferPrototype
, "byteLength")
67 const getTypedArrayBuffer
=
68 Object
.getOwnPropertyDescriptor(typedArrayPrototype
, "buffer").get;
69 const getTypedArrayByteLength
=
70 Object
.getOwnPropertyDescriptor(typedArrayPrototype
, "byteLength")
72 const getTypedArrayByteOffset
=
73 Object
.getOwnPropertyDescriptor(typedArrayPrototype
, "byteOffset")
76 Object
.getOwnPropertyDescriptor(viewPrototype
, "buffer").get;
77 const getViewByteLength
=
78 Object
.getOwnPropertyDescriptor(viewPrototype
, "byteLength").get;
79 const getViewByteOffset
=
80 Object
.getOwnPropertyDescriptor(viewPrototype
, "byteOffset").get;
82 getBigInt64
: viewGetInt64
,
83 getBigUint64
: viewGetUint64
,
84 getFloat32
: viewGetFloat32
,
85 getFloat64
: viewGetFloat64
,
87 getInt16
: viewGetInt16
,
88 getInt32
: viewGetInt32
,
89 getUint8
: viewGetUint8
,
90 getUint16
: viewGetUint16
,
91 getUint32
: viewGetUint32
,
92 setFloat32
: viewSetFloat32
,
93 setFloat64
: viewSetFloat64
,
94 setUint8
: viewSetUint8
,
95 setUint16
: viewSetUint16
,
96 setUint32
: viewSetUint32
,
97 setBigUint64
: viewSetUint64
,
101 * Returns an ArrayBuffer for encoding generated from the provided
104 const bufferFromArgs
= ($, $s
) => {
106 // Try just getting the array buffer associated with the first
107 // argument and returning it if possible.
108 return toArrayBuffer($);
110 // There is no array buffer associated with the first argument.
112 // Construct a string and convert it to an array buffer instead.
118 (result
, ucsCharacter
, index
) => (
119 call(viewSetUint16
, result
, [
121 getCodeUnit(ucsCharacter
, 0),
124 new View(new Buffer(string
.length
* 2)),
128 typeof $ === "string"
130 : hasOwnProperty($, "raw")
133 ...objectCreate(argumentIterablePrototype
, {
143 * Returns the result of decoding the provided base16 string into an
146 * ※ This function is not exposed.
148 const decodeBase16
= (source
) => {
152 const code
= getCodeUnit(ucsCharacter
, 0);
153 const result
= code
>= 0x30 && code
<= 0x39
155 : code
>= 0x41 && code
<= 0x46
157 : code
>= 0x61 && code
<= 0x66
161 // The source contains an invalid character.
162 throw new RangeError(
163 `Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
166 // The source contains a valid character with a recognized
172 const { length
} = u4s
;
173 if (length
% 2 === 1) {
174 // The length is such that an entire letter would be dropped during
175 // a forgiving decode.
176 throw new RangeError(
177 `Piscēs: Base16 string has invalid length: ${source}.`,
180 // Every letter contributes at least some bits to the result.
181 const dataView
= new View(new Buffer(floor(length
/ 2)));
182 for (let index
= 0; index
< length
- 1;) {
183 // Iterate over the characters and assign their bits to the
185 call(viewSetUint8
, dataView
, [
187 (u4s
[index
] << 4) | u4s
[++index
, index
++],
190 return call(getViewBuffer
, dataView
, []);
195 * Returns the result of decoding the provided base32 string into an
198 * If the second argument is truthy, uses Crockford’s encoding rather
199 * than the RFC’s (see <https://www.crockford.com/base32.html>). This
200 * is more human‐friendly and tolerant. Check digits are not supported.
202 * ※ This function is not exposed.
204 const decodeBase32
= (source
, wrmg
) => {
207 ? stringReplace(source
, /-/gu
, "")
208 : source
.length
% 8 === 0
209 ? stringReplace(source
, /(?:=|={3,4}|={6})$/u, "")
212 const code
= getCodeUnit(ucsCharacter
, 0);
214 ? code
>= 0x30 && code
<= 0x39
216 : code
>= 0x41 && code
<= 0x48
220 : code
>= 0x4A && code
<= 0x4B
224 : code
>= 0x4D && code
<= 0x4E
228 : code
>= 0x50 && code
<= 0x54
231 : code
>= 0x56 && code
<= 0x5A
233 : code
>= 0x61 && code
<= 0x68
237 : code
>= 0x6A && code
<= 0x6B
241 : code
>= 0x6D && code
<= 0x6E
245 : code
>= 0x70 && code
<= 0x74
248 : code
>= 0x76 && code
<= 0x7A
251 : code
>= 0x41 && code
<= 0x5A
253 : code
>= 0x61 && code
<= 0x7A
254 ? code
- 97 // same result as above; case insensitive
255 : code
>= 0x32 && code
<= 0x37
256 ? code
- 24 // digits 2–7 map to 26–31
259 // The source contains an invalid character.
260 throw new RangeError(
261 `Piscēs: Invalid character in Base32: ${ucsCharacter}.`,
264 // The source contains a valid character with a recognized
270 const { length
} = u5s
;
271 const lengthMod8
= length
% 8;
272 if (lengthMod8
=== 1 || lengthMod8
=== 3 || lengthMod8
=== 6) {
273 // The length is such that an entire letter would be dropped during
274 // a forgiving decode.
275 throw new RangeError(
276 `Piscēs: Base32 string has invalid length: ${source}.`,
279 // Every letter contributes at least some bits to the result.
280 const dataView
= new View(new Buffer(floor(length
* 5 / 8)));
281 for (let index
= 0; index
< length
- 1;) {
282 // Iterate over the characters and assign their bits to the
285 // The final index is not handled; if the string is not divisible
286 // by 8, some bits might be dropped. This matches the “forgiving
287 // decode” behaviour specified by WhatW·G for base64.
288 const dataIndex
= ceil(index
* 5 / 8);
289 const remainder
= index
% 8;
290 call(viewSetUint8
, dataView
, [
293 ? u5s
[index
] << 3 | u5s
[++index
] >> 2
295 ? u5s
[index
] << 6 | u5s
[++index
] << 1 | u5s
[++index
] >> 4
297 ? u5s
[index
] << 4 | u5s
[++index
] >> 1
299 ? u5s
[index
] << 7 | u5s
[++index
] << 2 | u5s
[++index
] >> 3
300 : u5s
[index
] << 5 | u5s
[++index
, index
++], // remainder === 6
303 return call(getViewBuffer
, dataView
, []);
308 * Returns the result of decoding the provided base64 string into an
311 * ※ This function is not exposed.
313 const decodeBase64
= (source
, safe
= false) => {
315 source
.length
% 4 === 0
316 ? stringReplace(source
, /={1,2}$/u, "")
319 const code
= getCodeUnit(ucsCharacter
, 0);
320 const result
= code
>= 0x41 && code
<= 0x5A
322 : code
>= 0x61 && code
<= 0x7A
324 : code
>= 0x30 && code
<= 0x39
326 : code
=== (safe
? 0x2D : 0x2B)
328 : code
=== (safe
? 0x5F : 0x2F)
332 // The source contains an invalid character.
333 throw new RangeError(
334 `Piscēs: Invalid character in Base64: ${ucsCharacter}.`,
337 // The source contains a valid character with a recognized
343 const { length
} = u6s
;
344 if (length
% 4 === 1) {
345 // The length is such that an entire letter would be dropped during
346 // a forgiving decode.
347 throw new RangeError(
348 `Piscēs: Base64 string has invalid length: ${source}.`,
351 // Every letter contributes at least some bits to the result.
352 const dataView
= new View(new Buffer(floor(length
* 3 / 4)));
353 for (let index
= 0; index
< length
- 1;) {
354 // Iterate over the characters and assign their bits to the
357 // The final index is not handled; if the string is not divisible
358 // by 4, some bits might be dropped. This matches the “forgiving
359 // decode” behaviour specified by WhatW·G for base64.
360 const dataIndex
= ceil(index
* 3 / 4);
361 const remainder
= index
% 4;
362 call(viewSetUint8
, dataView
, [
365 ? u6s
[index
] << 2 | u6s
[++index
] >> 4
367 ? u6s
[index
] << 4 | u6s
[++index
] >> 2
368 : u6s
[index
] << 6 | u6s
[++index
, index
++], // remainder === 2
371 return call(getViewBuffer
, dataView
, []);
376 * Returns the result of encoding the provided ArrayBuffer into a
379 * ※ This function is not exposed.
381 const encodeBase16
= (buffer
) => {
382 const dataView
= new View(buffer
);
383 const byteLength
= call(getBufferByteLength
, buffer
, []);
384 const minimumLengthOfResults
= byteLength
* 2;
385 const resultingCodeUnits
= fill(
387 binaryCodeUnitIterablePrototype
,
388 { length
: { value
: minimumLengthOfResults
} },
392 for (let index
= 0; index
< byteLength
;) {
393 // Iterate over the bytes and generate code units for them.
394 const codeUnitIndex
= index
* 2;
395 const datum
= call(viewGetUint8
, dataView
, [index
++]);
396 const u4s
= [datum
>> 4, datum
& 0xF];
397 for (let u4i
= 0; u4i
< 2; ++u4i
) {
398 // Handle the high four bits, then the low four bits.
400 const result
= u4
< 10 ? u4
+ 48 : u4
< 16 ? u4
+ 55 : -1;
402 // No mapping exists for these four bits.
404 // ※ This shouldn’t be possible!
405 throw new RangeError(
406 `Piscēs: Unexpected Base16 value: ${u4}.`,
409 // A mapping exists for the bits.
410 resultingCodeUnits
[codeUnitIndex
+ u4i
] = result
;
414 return stringFromCodeUnits(...resultingCodeUnits
);
418 * Returns the result of encoding the provided ArrayBuffer into a
421 * ※ This function is not exposed.
423 const encodeBase32
= (buffer
, wrmg
= false) => {
424 const dataView
= new View(buffer
);
425 const byteLength
= call(getBufferByteLength
, buffer
, []);
426 const minimumLengthOfResults
= ceil(byteLength
* 8 / 5);
427 const fillByte
= wrmg
? 0x2D : 0x3D;
428 const resultingCodeUnits
= fill(
430 binaryCodeUnitIterablePrototype
,
433 value
: minimumLengthOfResults
+
434 (8 - (minimumLengthOfResults
% 8)) % 8,
440 for (let index
= 0; index
< byteLength
;) {
441 // Iterate over the bytes and generate code units for them.
442 const codeUnitIndex
= ceil(index
* 8 / 5);
443 const currentIndex
= codeUnitIndex
+ +(
444 0b01011 & 1 << index
% 5 &&
445 resultingCodeUnits
[codeUnitIndex
] != fillByte
446 ); // bytes 0, 1 & 3 handle two letters; this is for the second
447 const remainder
= currentIndex
% 8;
448 const currentByte
= call(viewGetUint8
, dataView
, [index
]);
450 0b01011010 & 1 << remainder
&& ++index
< byteLength
451 // digits 1, 3, 4 & 6 span multiple bytes
452 ? call(viewGetUint8
, dataView
, [index
])
454 const u5
= remainder
=== 0
457 ? (currentByte
& 0b00000111) << 2 | nextByte
>> 6
459 ? (currentByte
& 0b00111111) >> 1
461 ? (currentByte
& 0b00000001) << 4 | nextByte
>> 4
463 ? (currentByte
& 0b00001111) << 1 | nextByte
>> 7
465 ? (currentByte
& 0b01111111) >> 2
467 ? (currentByte
& 0b00000011) << 3 | nextByte
>> 5
468 : (++index
, currentByte
& 0b00011111); // remainder === 7
470 ? u5
< 10 ? u5
+ 48 : u5
< 18
491 // No mapping exists for these five bits.
493 // ※ This shouldn’t be possible!
494 throw new RangeError(`Piscēs: Unexpected Base32 value: ${u5}.`);
496 // A mapping exists for the bits.
497 resultingCodeUnits
[currentIndex
] = result
;
500 const answer
= stringFromCodeUnits(...resultingCodeUnits
);
501 return wrmg
? answer
.replace(/-+$/u, "") : answer
;
505 * Returns the result of encoding the provided ArrayBuffer into a
508 * ※ This function is not exposed.
510 const encodeBase64
= (buffer
, safe
= false) => {
511 const dataView
= new View(buffer
);
512 const byteLength
= call(getBufferByteLength
, buffer
, []);
513 const minimumLengthOfResults
= ceil(byteLength
* 4 / 3);
514 const resultingCodeUnits
= fill(
516 binaryCodeUnitIterablePrototype
,
519 value
: minimumLengthOfResults
+
520 (4 - (minimumLengthOfResults
% 4)) % 4,
526 for (let index
= 0; index
< byteLength
;) {
527 // Iterate over the bytes and generate code units for them.
528 const codeUnitIndex
= ceil(index
* 4 / 3);
529 const currentIndex
= codeUnitIndex
+ +(
530 index
% 3 === 0 && resultingCodeUnits
[codeUnitIndex
] != 0x3D
531 ); // every third byte handles two letters; this is for the second
532 const remainder
= currentIndex
% 4;
533 const currentByte
= call(viewGetUint8
, dataView
, [index
]);
534 const nextByte
= remainder
% 3 && ++index
< byteLength
535 // digits 1 & 2 span multiple bytes
536 ? call(viewGetUint8
, dataView
, [index
])
538 const u6
= remainder
=== 0
541 ? (currentByte
& 0b00000011) << 4 | nextByte
>> 4
543 ? (currentByte
& 0b00001111) << 2 | nextByte
>> 6
544 : (++index
, currentByte
& 0b00111111); // remainder === 3
545 const result
= u6
< 26
552 ? (safe
? 0x2D : 0x2B)
554 ? (safe
? 0x5F : 0x2F)
557 // No mapping exists for these six bits.
559 // ※ This shouldn’t be possible!
560 throw new RangeError(`Piscēs: Unexpected Base64 value: ${u6}.`);
562 // A mapping exists for the bits.
563 resultingCodeUnits
[currentIndex
] = result
;
566 return stringFromCodeUnits(...resultingCodeUnits
);
570 * Returns a source string generated from the arguments passed to a
573 * ※ This function is not exposed.
575 const sourceFromArgs
= ($, $s
) =>
577 typeof $ === "string" ? $ : hasOwnProperty($, "raw")
580 ...objectCreate(argumentIterablePrototype
, {
590 * Returns a slice of the provided value according to the algorithm of
591 * `ArrayBuffer::slice` (or `SharedArrayBuffer::slice`).
593 * ☡ This function throws if the provided value is not an array buffer.
595 export const arrayBufferSlice
= ($, start
, end
, ...args
) =>
597 isSharedArrayBuffer($) ? sharedBufferSlice
: bufferSlice
,
603 argumentIterablePrototype
,
604 { args
: { value
: args
} },
610 * Returns an ArrayBuffer generated from the provided base16 string.
612 * This function can also be used as a tag for a template literal. The
613 * literal will be interpreted akin to `String.raw`.
615 * ☡ This function throws if the provided string is not a valid base16
618 export const base16Binary
= ($, ...$s
) =>
619 decodeBase16(sourceFromArgs($, $s
));
622 * Returns a (big‐endian) base16 string created from the provided typed
623 * array, buffer, or (16‐bit) string.
625 * This function can also be used as a tag for a template literal. The
626 * literal will be interpreted akin to `String.raw`.
628 export const base16String
= ($, ...$s
) =>
629 encodeBase16(bufferFromArgs($, $s
));
632 * Returns an ArrayBuffer generated from the provided base32 string.
634 * This function can also be used as a tag for a template literal. The
635 * literal will be interpreted akin to `String.raw`.
637 * ☡ This function throws if the provided string is not a valid base32
640 export const base32Binary
= ($, ...$s
) =>
641 decodeBase32(sourceFromArgs($, $s
));
644 * Returns a (big‐endian) base32 string created from the provided typed
645 * array, buffer, or (16‐bit) string.
647 * This function can also be used as a tag for a template literal. The
648 * literal will be interpreted akin to `String.raw`.
650 export const base32String
= ($, ...$s
) =>
651 encodeBase32(bufferFromArgs($, $s
));
654 * Returns an ArrayBuffer generated from the provided base64 string.
656 * This function can also be used as a tag for a template literal. The
657 * literal will be interpreted akin to `String.raw`.
659 * ☡ This function throws if the provided string is not a valid base64
662 export const base64Binary
= ($, ...$s
) =>
663 decodeBase64(sourceFromArgs($, $s
));
666 * Returns a (big‐endian) base64 string created from the provided typed
667 * array, buffer, or (16‐bit) string.
669 * This function can also be used as a tag for a template literal. The
670 * literal will be interpreted akin to `String.raw`.
672 export const base64String
= ($, ...$s
) =>
673 encodeBase64(bufferFromArgs($, $s
));
676 * Returns an ArrayBuffer generated from the provided filename‐safe
679 * This function can also be used as a tag for a template literal. The
680 * literal will be interpreted akin to `String.raw`.
682 * ☡ This function throws if the provided string is not a valid
683 * filename‐safe base64 string.
685 export const filenameSafeBase64Binary
= ($, ...$s
) =>
686 decodeBase64(sourceFromArgs($, $s
), true);
689 * Returns a (big‐endian) filename‐safe base64 string created from the
690 * provided typed array, buffer, or (16‐bit) string.
692 * This function can also be used as a tag for a template literal. The
693 * literal will be interpreted akin to `String.raw`.
695 export const filenameSafeBase64String
= ($, ...$s
) =>
696 encodeBase64(bufferFromArgs($, $s
), true);
700 * Returns the signed 8‐bit integral value in the provided array
701 * buffer or array buffer view at the provided byte offset.
703 * ※ The retrieved value will be big·endian unless a third argument
704 * is specified and truthy.
706 * ※ This is similar to `DataView::getInt8`, but works on all array
707 * buffers and array buffer views and returns a big·int.
709 * ☡ This function throws if the first argument is not an array
710 * buffer, data view, or typed array.
712 get8BitSignedIntegralItem
,
715 * Returns the unsigned 8‐bit integral value in the provided array
716 * buffer or array buffer view at the provided byte offset.
718 * ※ The retrieved value will be big·endian unless a third argument
719 * is specified and truthy.
721 * ※ This is similar to `DataView::getUint8`, but works on all array
722 * buffers and array buffer views and returns a big·int.
724 * ☡ This function throws if the first argument is not an array
725 * buffer, data view, or typed array.
727 get8BitUnsignedIntegralItem
,
730 * Returns the signed 16‐bit integral value in the provided array
731 * buffer or array buffer view at the provided byte offset.
733 * ※ The retrieved value will be big·endian unless a third argument
734 * is specified and truthy.
736 * ※ This is similar to `DataView::getInt16`, but works on all array
737 * buffers and array buffer views and returns a big·int.
739 * ☡ This function throws if the first argument is not an array
740 * buffer, data view, or typed array.
742 get16BitSignedIntegralItem
,
745 * Returns the unsigned 16‐bit integral value in the provided array
746 * buffer or array buffer view at the provided byte offset.
748 * ※ The retrieved value will be big·endian unless a third argument
749 * is specified and truthy.
751 * ※ This is similar to `DataView::getUint16`, but works on all
752 * array buffers and array buffer views and returns a big·int.
754 * ☡ This function throws if the first argument is not an array
755 * buffer, data view, or typed array.
757 get16BitUnsignedIntegralItem
,
760 * Returns the 32‐bit floating point value in the provided array
761 * buffer or array buffer view at the provided byte offset.
763 * ※ The retrieved value will be big·endian unless a third argument
764 * is specified and truthy.
766 * ※ This is similar to `DataView::getFloat32`, but works on all
767 * array buffers and array buffer views.
769 * ☡ This function throws if the first argument is not an array
770 * buffer, data view, or typed array.
772 get32BitFloatingPointItem
,
775 * Returns the signed 32‐bit integral value in the provided array
776 * buffer or array buffer view at the provided byte offset.
778 * ※ The retrieved value will be big·endian unless a third argument
779 * is specified and truthy.
781 * ※ This is similar to `DataView::getInt32`, but works on all array
782 * buffers and array buffer views and returns a big·int.
784 * ☡ This function throws if the first argument is not an array
785 * buffer, data view, or typed array.
787 get32BitSignedIntegralItem
,
790 * Returns the unsigned 32‐bit integral value in the provided array
791 * buffer or array buffer view at the provided byte offset.
793 * ※ The retrieved value will be big·endian unless a third argument
794 * is specified and truthy.
796 * ※ This is similar to `DataView::getUint32`, but works on all
797 * array buffers and array buffer views and returns a big·int.
799 * ☡ This function throws if the first argument is not an array
800 * buffer, data view, or typed array.
802 get32BitUnsignedIntegralItem
,
805 * Returns the 64‐bit floating point value in the provided array
806 * buffer or array buffer view at the provided byte offset.
808 * ※ The retrieved value will be big·endian unless a third argument
809 * is specified and truthy.
811 * ※ This is similar to `DataView::getFloat64`, but works on all
812 * array buffers and array buffer views.
814 * ☡ This function throws if the first argument is not an array
815 * buffer, data view, or typed array.
817 get64BitFloatingPointItem
,
820 * Returns the signed 64‐bit integral value in the provided array
821 * buffer or array buffer view at the provided byte offset.
823 * ※ The retrieved value will be big·endian unless a third argument
824 * is specified and truthy.
826 * ※ This is similar to `DataView::getBigInt64`, but works on all
827 * array buffers and array buffer views.
829 * ☡ This function throws if the first argument is not an array
830 * buffer, data view, or typed array.
832 get64BitSignedIntegralItem
,
835 * Returns the unsigned 64‐bit integral value in the provided array
836 * buffer or array buffer view at the provided byte offset.
838 * ※ The retrieved value will be big·endian unless a third argument
839 * is specified and truthy.
841 * ※ This is similar to `DataView::getBigUint64`, but works on all
842 * array buffers and array buffer views.
844 * ☡ This function throws if the first argument is not an array
845 * buffer, data view, or typed array.
847 get64BitUnsignedIntegralItem
,
850 * Sets the 8‐bit integral value in the provided array buffer or
851 * array buffer view at the provided byte offset to the provided
854 * ※ The value will be set as big·endian unless a fourth argument is
855 * specified and truthy.
857 * ※ This is similar to `DataView::setInt8`, but works on all array
858 * buffers and array buffer views and accepts both numeric and
861 * ※ It doesn’t matter whether the provided value is signed or
862 * unsigned, as the algorithm will cast one to the other.
864 * ☡ This function throws if the first argument is not an array
865 * buffer, data view, or typed array.
870 * Sets the 16‐bit integral value in the provided array buffer or
871 * array buffer view at the provided byte offset to the provided
874 * ※ The value will be set as big·endian unless a fourth argument is
875 * specified and truthy.
877 * ※ This is similar to `DataView::setInt16`, but works on all array
878 * buffers and array buffer views and accepts both numeric and
881 * ※ It doesn’t matter whether the provided value is signed or
882 * unsigned, as the algorithm will cast one to the other.
884 * ☡ This function throws if the first argument is not an array
885 * buffer, data view, or typed array.
887 set16BitIntegralItem
,
890 * Sets the 32‐bit floating point value in the provided array buffer
891 * or array buffer view at the provided byte offset to the provided
894 * ※ The value will be set as big·endian unless a fourth argument is
895 * specified and truthy.
897 * ※ This is similar to `DataView::setFloat32`, but works on all
898 * array buffers and array buffer views.
900 * ☡ This function throws if the first argument is not an array
901 * buffer, data view, or typed array.
903 set32BitFloatingPointItem
,
906 * Sets the 32‐bit integral value in the provided array buffer or
907 * array buffer view at the provided byte offset to the provided
910 * ※ The value will be set as big·endian unless a fourth argument is
911 * specified and truthy.
913 * ※ This is similar to `DataView::setInt32`, but works on all array
914 * buffers and array buffer views and accepts both numeric and
917 * ※ It doesn’t matter whether the provided value is signed or
918 * unsigned, as the algorithm will cast one to the other.
920 * ☡ This function throws if the first argument is not an array
921 * buffer, data view, or typed array.
923 set32BitIntegralItem
,
926 * Sets the 64‐bit floating point value in the provided array buffer
927 * or array buffer view at the provided byte offset to the provided
930 * ※ The value will be set as big·endian unless a fourth argument is
931 * specified and truthy.
933 * ※ This is similar to `DataView::setFloat64`, but works on all
934 * array buffers and array buffer views.
936 * ☡ This function throws if the first argument is not an array
937 * buffer, data view, or typed array.
939 set64BitFloatingPointItem
,
942 * Sets the 64‐bit integral value in the provided array buffer or
943 * array buffer view at the provided byte offset to the provided
946 * ※ The value will be set as big·endian unless a fourth argument is
947 * specified and truthy.
949 * ※ This is similar to `DataView::setInt32`, but works on all array
950 * buffers and array buffer views.
952 * ※ It doesn’t matter whether the provided value is signed or
953 * unsigned, as the algorithm will cast one to the other.
955 * ☡ This function throws if the first argument is not an array
956 * buffer, data view, or typed array, or if the third argument is not
959 set64BitIntegralItem
,
961 const makeBigInt
= BigInt
;
962 const { asUintN
} = BigInt
;
963 const makeNumber
= Number
;
965 const viewMap
= new WeakMap();
966 const view
= ($) => {
967 const buffer
= toArrayBuffer($);
968 if (viewMap
.has(buffer
)) {
969 // A view has already been allocated for this buffer; use it.
970 return viewMap
.get(buffer
);
972 // No view has been created for this buffer yet.
973 const result
= new View(buffer
);
974 viewMap
.set(buffer
, result
);
980 get8BitSignedIntegralItem
: ($, byteOffset
, ...args
) =>
982 call(viewGetInt8
, view($), [
983 getByteOffset($) + byteOffset
,
985 argumentIterablePrototype
,
986 { args
: { value
: args
} },
990 get8BitUnsignedIntegralItem
: ($, byteOffset
, ...args
) =>
992 call(viewGetUint8
, view($), [
993 getByteOffset($) + byteOffset
,
995 argumentIterablePrototype
,
996 { args
: { value
: args
} },
1000 get16BitSignedIntegralItem
: ($, byteOffset
, ...args
) =>
1002 call(viewGetInt16
, view($), [
1003 getByteOffset($) + byteOffset
,
1005 argumentIterablePrototype
,
1006 { args
: { value
: args
} },
1010 get16BitUnsignedIntegralItem
: ($, byteOffset
, ...args
) =>
1012 call(viewGetUint16
, view($), [
1013 getByteOffset($) + byteOffset
,
1015 argumentIterablePrototype
,
1016 { args
: { value
: args
} },
1020 get32BitFloatingPointItem
: ($, byteOffset
, ...args
) =>
1021 call(viewGetFloat32
, view($), [
1022 getByteOffset($) + byteOffset
,
1024 argumentIterablePrototype
,
1025 { args
: { value
: args
} },
1028 get32BitSignedIntegralItem
: ($, byteOffset
, ...args
) =>
1030 call(viewGetInt32
, view($), [
1031 getByteOffset($) + byteOffset
,
1033 argumentIterablePrototype
,
1034 { args
: { value
: args
} },
1038 get32BitUnsignedIntegralItem
: ($, byteOffset
, ...args
) =>
1040 call(viewGetUint32
, view($), [
1041 getByteOffset($) + byteOffset
,
1043 argumentIterablePrototype
,
1044 { args
: { value
: args
} },
1048 get64BitFloatingPointItem
: ($, byteOffset
, ...args
) =>
1049 call(viewGetFloat64
, view($), [
1050 getByteOffset($) + byteOffset
,
1052 argumentIterablePrototype
,
1053 { args
: { value
: args
} },
1056 get64BitSignedIntegralItem
: ($, byteOffset
, ...args
) =>
1057 call(viewGetInt64
, view($), [
1058 getByteOffset($) + byteOffset
,
1060 argumentIterablePrototype
,
1061 { args
: { value
: args
} },
1064 get64BitUnsignedIntegralItem
: ($, byteOffset
, ...args
) =>
1065 call(viewGetUint64
, view($), [
1066 getByteOffset($) + byteOffset
,
1068 argumentIterablePrototype
,
1069 { args
: { value
: args
} },
1072 set8BitIntegralItem
: ($, byteOffset
, value
, ...args
) =>
1073 call(viewSetUint8
, view($), [
1074 getByteOffset($) + byteOffset
,
1077 argumentIterablePrototype
,
1078 { args
: { value
: args
} },
1081 set16BitIntegralItem
: ($, byteOffset
, value
, ...args
) =>
1082 call(viewSetUint16
, view($), [
1083 getByteOffset($) + byteOffset
,
1086 argumentIterablePrototype
,
1087 { args
: { value
: args
} },
1090 set32BitFloatingPointItem
: ($, byteOffset
, value
, ...args
) =>
1091 call(viewSetFloat32
, view($), [
1092 getByteOffset($) + byteOffset
,
1095 argumentIterablePrototype
,
1096 { args
: { value
: args
} },
1099 set32BitIntegralItem
: ($, byteOffset
, value
, ...args
) =>
1100 call(viewSetUint32
, view($), [
1101 getByteOffset($) + byteOffset
,
1104 argumentIterablePrototype
,
1105 { args
: { value
: args
} },
1108 set64BitFloatingPointItem
: ($, byteOffset
, value
, ...args
) =>
1109 call(viewSetFloat64
, view($), [
1110 getByteOffset($) + byteOffset
,
1113 argumentIterablePrototype
,
1114 { args
: { value
: args
} },
1117 set64BitIntegralItem
: ($, byteOffset
, value
, ...args
) =>
1118 call(viewSetUint64
, view($), [
1119 getByteOffset($) + byteOffset
,
1122 argumentIterablePrototype
,
1123 { args
: { value
: args
} },
1130 * Returns the byte length for the provided array buffer or array
1133 * ☡ This function throws if the provided value is not an array buffer,
1134 * data view, or typed array.
1136 export const getByteLength
= ($) => {
1138 // Attempt to get the byte length from the provided value as an
1140 return call(getBufferByteLength
, $, []);
1142 // The provided value is not an `ArrayBuffer`.
1146 // Attempt to get the byte length from the provided value as a
1147 // `SharedArrayBuffer`.
1148 return call(getSharedBufferByteLength
, $, []);
1150 // The provided value is not a `SharedArrayBuffer`.
1154 // Attempt to get the byte length from the provided value as a
1156 return call(getViewByteLength
, $, []);
1158 // The provided value is not a data view.
1162 // Attempt to get the byte length from the provided value as a
1164 return call(getTypedArrayByteLength
, $, []);
1166 // The provided value is not a typed array.
1169 throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
1173 * Returns the byte offset for the provided array buffer or array
1176 * ※ This function always returns `0` for array buffers.
1178 * ☡ This function throws if the provided value is not an array buffer,
1179 * data view, or typed array.
1181 export const getByteOffset
= ($) => {
1182 if (isArrayBuffer($)) {
1183 // The provided value is an array buffer.
1187 // Attempt to get the byte offset from the provided value as a
1189 return call(getViewByteOffset
, $, []);
1191 // The provided value is not a data view.
1195 // Attempt to get the byte offset from the provided value as a
1197 return call(getTypedArrayByteOffset
, $, []);
1199 // The provided value is not a typed array.
1202 throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
1207 * Returns whether the provided value is a view on an underlying array
1210 * ※ This function returns true for typed arrays and data views.
1212 export const { isView
: isArrayBufferView
} = Buffer
;
1215 * Returns whether the provided value is an array buffer.
1217 * ※ This function returns true for both `ArrayBuffer`s and
1218 * `SharedArrayBuffer`s.
1220 export const isArrayBuffer
= ($) => {
1222 // Try to see if the provided argument has array buffer internal
1223 // slots and return true if so.
1224 return call(getBufferByteLength
, $, []), true;
1226 // The provided argument does not have array buffer internal slots.
1230 // Try to see if the provided argument has array buffer internal
1231 // slots and return true if so.
1232 return call(getSharedBufferByteLength
, $, []), true;
1234 // The provided argument does not have array buffer internal slots.
1241 * Returns whether the provided value is a base16 string.
1243 * ※ This function returns false if the provided value is not a string
1246 export const isBase16
= ($) => {
1247 if (typeof $ !== "string") {
1248 // The provided value is not a string.
1251 // The provided value is a string.
1252 const source
= stringReplace($, /[\t\n\f\r ]+/gu, "");
1253 return source
.length
% 2 !== 1 &&
1254 call(reExec
, /[^0-9A-F]/iu, [source
]) === null;
1259 * Returns whether the provided value is a base32 string.
1261 * ※ This function returns false if the provided value is not a string
1264 export const isBase32
= ($) => {
1265 if (typeof $ !== "string") {
1266 // The provided value is not a string.
1269 // The provided value is a string.
1270 const source
= stringReplace($, /[\t\n\f\r ]+/gu, "");
1271 const trimmed
= source
.length
% 8 === 0
1272 ? stringReplace(source
, /(?:=|={3,4}|={6})$/u, "")
1274 return trimmed
.length
% 8 !== 1 &&
1275 call(reExec
, /[^2-7A-Z/]/iu
, [trimmed
]) === null;
1280 * Returns whether the provided value is a Base64 string.
1282 * ※ This function returns false if the provided value is not a string
1285 export const isBase64
= ($) => {
1286 if (typeof $ !== "string") {
1287 // The provided value is not a string.
1290 // The provided value is a string.
1291 const source
= stringReplace($, /[\t\n\f\r ]+/gu, "");
1292 const trimmed
= source
.length
% 4 === 0
1293 ? stringReplace(source
, /={1,2}$/u, "")
1295 return trimmed
.length
% 4 !== 1 &&
1296 call(reExec
, /[^0-9A-Za-z+\/]/u, [trimmed
]) === null;
1301 * Returns whether the provided value is a filename‐safe base64 string.
1303 * ※ This function returns false if the provided value is not a string
1306 export const isFilenameSafeBase64
= ($) => {
1307 if (typeof $ !== "string") {
1308 // The provided value is not a string.
1311 // The provided value is a string.
1312 const source
= stringReplace($, /[\t\n\f\r ]+/gu, "");
1313 const trimmed
= source
.length
% 4 === 0
1314 ? stringReplace(source
, /={1,2}$/u, "")
1316 return trimmed
.length
% 4 !== 1 &&
1317 call(reExec
, /[^0-9A-Za-z_-]/u, [trimmed
]) === null;
1321 /** Returns whether the provided value is a shared array buffer. */
1322 export const isSharedArrayBuffer
= ($) => {
1324 // Try to see if the provided argument has shared array buffer
1325 // internal slots and return true if so.
1326 return call(getSharedBufferByteLength
, $, []), true;
1328 // The provided argument does not have data view internal slots.
1333 /** Returns whether the provided value is a typed array. */
1334 export const isTypedArray
= ($) => {
1336 // Try to see if the provided argument has typed array internal
1337 // slots and return true if so.
1338 return call(getTypedArrayBuffer
, $, []), true;
1340 // The provided argument does not have typed array internal slots.
1346 * Returns whether the provided value is a W·R·M·G (Crockford) base32
1347 * string. Check digits are not supported.
1349 * ※ This function returns false if the provided value is not a string
1352 export const isWRMGBase32
= ($) => {
1353 if (typeof $ !== "string") {
1354 // The provided value is not a string.
1357 // The provided value is a string.
1358 const source
= stringReplace($, /[\t\n\f\r ]+/gu, "");
1359 const trimmed
= stringReplace(source
, /-/gu
, "");
1360 return trimmed
.length
% 8 !== 1 &&
1361 call(reExec
, /[^0-9A-TV-Z]/iu, [trimmed
]) === null;
1366 * Returns the array buffer associated with the provided object.
1368 * ☡ This function throws if the provided object is not a data view or
1371 export const toArrayBuffer
= ($) => {
1372 if (isArrayBuffer($)) {
1373 // The provided argument has array buffer internal slots.
1376 // The provided argument does not have array buffer internal slots.
1378 // The provided argument has typed array internal slots.
1379 return call(getTypedArrayBuffer
, $, []);
1384 // The provided argument has data view internal slots.
1385 return call(getViewBuffer
, $, []);
1389 throw new TypeError(`Piscēs: Not an array buffer or view: ${$}.`);
1394 * Returns an ArrayBuffer generated from the provided W·R·M·G
1395 * (Crockford) base32 string.
1397 * This function can also be used as a tag for a template literal. The
1398 * literal will be interpreted akin to `String.raw`.
1400 * ☡ This function throws if the provided string is not a valid W·R·M·G
1403 export const wrmgBase32Binary
= ($, ...$s
) =>
1404 decodeBase32(sourceFromArgs($, $s
), true);
1407 * Returns a (big‐endian) W·R·M·G (Crockford) base32 string created
1408 * from the provided typed array, buffer, or (16‐bit) string.
1410 * This function can also be used as a tag for a template literal. The
1411 * literal will be interpreted akin to `String.raw`.
1413 export const wrmgBase32String
= ($, ...$s
) =>
1414 encodeBase32(bufferFromArgs($, $s
), true);