UNPKG

@thi.ng/transducers-binary

Version:

Binary data related transducers & reducers

267 lines (266 loc) 6.13 kB
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 };