@thi.ng/transducers-binary
Version:
Binary data related transducers & reducers
267 lines (266 loc) • 6.13 kB
JavaScript
import {
bytes16,
bytes24,
bytes32,
bytesF32,
bytesF64
} from "@thi.ng/binary/bytes";
import { unsupported } from "@thi.ng/errors/unsupported";
import { iterator } from "@thi.ng/transducers/iterator";
import { mapcat } from "@thi.ng/transducers/mapcat";
import { reduce } from "@thi.ng/transducers/reduce";
import { utf8Encode } from "./utf8.js";
const i8 = (x) => ["i8", x];
const i8array = (x) => ["i8a", x];
const u8 = (x) => ["u8", x];
const u8array = (x) => ["u8a", x];
const i16 = (x, le = false) => ["i16", x, le];
const i16array = (x, le = false) => [
"i16a",
x,
le
];
const u16 = (x, le = false) => ["u16", x, le];
const u16array = (x, le = false) => [
"u16a",
x,
le
];
const i24 = (x, le = false) => ["i24", x, le];
const i24array = (x, le = false) => [
"i24a",
x,
le
];
const u24 = (x, le = false) => ["u24", x, le];
const u24array = (x, le = false) => [
"u24a",
x,
le
];
const i32 = (x, le = false) => ["i32", x, le];
const i32array = (x, le = false) => [
"i32a",
x,
le
];
const u32 = (x, le = false) => ["u32", x, le];
const u32array = (x, le = false) => [
"u32a",
x,
le
];
const f32 = (x, le = false) => ["f32", x, le];
const f32array = (x, le = false) => [
"f32a",
x,
le
];
const f64 = (x, le = false) => ["f64", x, le];
const f64array = (x, le = false) => [
"f64a",
x,
le
];
const str = (x) => ["str", x];
function asBytes(src) {
return src ? iterator(asBytes(), src) : mapcat((x) => {
const val = x[1];
const le = x[2];
switch (x[0]) {
case "i8":
case "u8":
return [val];
case "i8a":
case "u8a":
return x[1];
case "i16":
case "u16":
return bytes16(val, le);
case "i16a":
case "u16a":
return mapcat((x2) => bytes16(x2, le), x[1]);
case "i24":
case "u24":
return bytes24(val, le);
case "i24a":
case "u24a":
return mapcat((x2) => bytes24(x2, le), x[1]);
case "i32":
case "u32":
return bytes32(val, le);
case "i32a":
case "u32a":
return mapcat((x2) => bytes32(x2, le), x[1]);
case "f32":
return bytesF32(val, le);
case "f32a":
return mapcat((x2) => bytesF32(x2, le), x[1]);
case "f64":
return bytesF64(val, le);
case "f64a":
return mapcat((x2) => bytesF64(x2, le), x[1]);
case "str":
return utf8Encode(x[1]);
default:
unsupported(`invalid struct item: ${x[0]}`);
}
});
}
function bytes(cap = 1024, src) {
let view;
let pos = 0;
const ensure = (acc, size) => {
if (pos + size <= cap) return acc;
cap *= 2;
const buf = new Uint8Array(cap);
buf.set(acc);
view = new DataView(buf.buffer);
return buf;
};
const setArray = (fn, stride, acc, x, le) => {
const n = x.length;
acc = ensure(acc, stride * n);
for (let i = 0; i < n; i++, pos += stride) {
view[fn](pos, x[i], le);
}
return acc;
};
return src ? reduce(bytes(cap), src) : [
() => new Uint8Array(cap),
(acc) => acc.subarray(0, pos),
(acc, [type, x, le = false]) => {
if (!view || view.buffer !== acc.buffer) {
cap = acc.byteLength;
view = new DataView(acc.buffer, acc.byteOffset);
}
switch (type) {
case "i8":
acc = ensure(acc, 1);
view.setInt8(pos, x);
pos++;
break;
case "i8a": {
const n = x.length;
acc = ensure(acc, n);
new Int8Array(acc.buffer, acc.byteOffset).set(
x,
pos
);
pos += n;
break;
}
case "u8":
acc = ensure(acc, 1);
view.setUint8(pos, x);
pos++;
break;
case "u8a": {
const n = x.length;
acc = ensure(acc, n);
acc.set(x, pos);
pos += n;
break;
}
case "i16":
acc = ensure(acc, 2);
view.setInt16(pos, x, le);
pos += 2;
break;
case "i16a":
acc = setArray("setInt16", 2, acc, x, le);
break;
case "u16":
acc = ensure(acc, 2);
view.setUint16(pos, x, le);
pos += 2;
break;
case "u16a":
acc = setArray("setUint16", 2, acc, x, le);
break;
case "i24":
acc = ensure(acc, 4);
view.setInt32(pos, x, le);
pos += 3;
break;
case "i24a":
acc = setArray("setInt32", 3, acc, x, le);
break;
case "u24":
acc = ensure(acc, 4);
view.setUint32(pos, x, le);
pos += 3;
break;
case "u24a":
acc = setArray("setUint32", 3, acc, x, le);
break;
case "i32":
acc = ensure(acc, 4);
view.setInt32(pos, x, le);
pos += 4;
break;
case "i32a":
acc = setArray("setInt32", 4, acc, x, le);
break;
case "u32":
acc = ensure(acc, 4);
view.setUint32(pos, x, le);
pos += 4;
break;
case "u32a":
acc = setArray("setUint32", 4, acc, x, le);
break;
case "f32":
acc = ensure(acc, 4);
view.setFloat32(pos, x, le);
pos += 4;
break;
case "f32a":
acc = setArray("setFloat32", 4, acc, x, le);
break;
case "f64":
acc = ensure(acc, 8);
view.setFloat64(pos, x, le);
pos += 8;
break;
case "f64a":
acc = setArray("setFloat64", 8, acc, x, le);
break;
case "str": {
let utf = utf8Encode(x);
acc = ensure(acc, utf.length);
acc.set(utf, pos);
pos += utf.length;
break;
}
default:
}
return acc;
}
];
}
export {
asBytes,
bytes,
f32,
f32array,
f64,
f64array,
i16,
i16array,
i24,
i24array,
i32,
i32array,
i8,
i8array,
str,
u16,
u16array,
u24,
u24array,
u32,
u32array,
u8,
u8array
};