UNPKG

c-structs

Version:
289 lines (288 loc) 6.57 kB
// src/index.ts var p = { float32: { size: 4, arrayType: Float32Array, getter: "getFloat32", setter: "setFloat32" }, float64: { size: 8, arrayType: Float64Array, getter: "getFloat64", setter: "setFloat64" }, uint16: { size: 2, arrayType: Uint16Array, getter: "getUint16", setter: "setUint16" }, uint32: { size: 4, arrayType: Uint32Array, getter: "getUint32", setter: "setUint32" }, uint64: { size: 8, arrayType: BigUint64Array, getter: "getBigUint64", setter: "setBigUint64" }, int16: { size: 2, arrayType: Int16Array, getter: "getInt16", setter: "setInt16" }, int32: { size: 4, arrayType: Int32Array, getter: "getInt32", setter: "setInt32" }, int64: { size: 8, arrayType: BigInt64Array, getter: "getBigInt64", setter: "setBigInt64" } }; var c = { float() { return p.float32; }, float2() { return [p.float32, p.float32]; }, float3() { return [p.float32, p.float32, p.float32]; }, float4() { return [p.float32, p.float32, p.float32, p.float32]; }, uint() { return p.uint32; }, uint2() { return [p.uint32, p.uint32]; }, uint3() { return [p.uint32, p.uint32, p.uint32]; }, uint4() { return [p.uint32, p.uint32, p.uint32, p.uint32]; }, int() { return p.int32; }, int2() { return [p.int32, p.int32]; }, int3() { return [p.int32, p.int32, p.int32]; }, int4() { return [p.int32, p.int32, p.int32, p.int32]; }, uint16() { return p.uint16; }, uint64() { return p.uint64; }, int16() { return p.int16; }, int64() { return p.int64; }, float64() { return p.float64; }, matrix3() { return [ p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32 ]; }, matrix4() { return [ p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32, p.float32 ]; }, /** * Create an array descriptor for nested structs. */ array(structDesc, length) { if (typeof structDesc.size !== "number" || typeof structDesc.create !== "function") { throw new Error("c.array: first arg must be a StructDescriptor"); } if (!Number.isInteger(length) || length <= 0) { throw new Error("c.array: length must be a positive integer"); } return { size: structDesc.size * length, create(buffer = new ArrayBuffer(structDesc.size * length), baseOffset = 0) { const arr = new Array(length); for (let i = 0; i < length; i++) { arr[i] = structDesc.create(buffer, baseOffset + i * structDesc.size); } Object.defineProperty(arr, "buffer", { get: () => buffer, enumerable: false }); return arr; } }; }, /** * Create a struct descriptor from a schema map. */ struct(schema) { let offset = 0; const fields = []; for (const [name, type] of Object.entries(schema)) { const fieldOffset = offset; let entry; if (Array.isArray(type)) { const elem = type[0]; entry = { kind: "vector", name, elem, length: type.length, offset: fieldOffset }; offset += elem.size * type.length; } else if (type.size && typeof type.create === "function" && Array.isArray(type.create())) { entry = { kind: "array", name, elemDesc: type, length: type.length, offset: fieldOffset }; offset += type.size * type.length; } else if (type.arrayType) { const elem = type; entry = { kind: "scalar", name, desc: elem, offset: fieldOffset }; offset += elem.size; } else if (type.size && typeof type.create === "function") { entry = { kind: "struct", name, desc: type, offset: fieldOffset }; offset += type.size; } else { throw new Error(`Unknown field type for "${name}"`); } fields.push(entry); } const totalSize = offset; class Ctor { buffer; baseOffset; __view; constructor(buffer = new ArrayBuffer(totalSize), baseOffset = 0) { this.buffer = buffer; this.baseOffset = baseOffset; this.__view = new DataView(buffer); for (const f of fields) { if (f.kind === "struct") { this[f.name] = f.desc.create(buffer, baseOffset + f.offset); } else if (f.kind === "array") { this[f.name] = c.array(f.elemDesc, f.length).create(buffer, baseOffset + f.offset); } } } } for (const f of fields) { const abs = f.offset; switch (f.kind) { case "scalar": Object.defineProperty(Ctor.prototype, f.name, { enumerable: true, get() { return this.__view[f.desc.getter]( this.baseOffset + abs, true ); }, set(v) { return this.__view[f.desc.setter]( this.baseOffset + abs, v, true ); } }); break; case "vector": { const Typed = f.elem.arrayType; Object.defineProperty(Ctor.prototype, f.name, { enumerable: true, get() { if (!this.hasOwnProperty("__" + f.name)) { Object.defineProperty(this, "__" + f.name, { value: new Typed( this.buffer, this.baseOffset + abs, f.length ), writable: false, enumerable: false }); } return this["__" + f.name]; }, set(arr) { const ta = this[f.name]; for (let i = 0; i < f.length; i++) ta[i] = arr[i]; } }); break; } } } return { size: totalSize, create(buffer, baseOffset) { return new Ctor(buffer, baseOffset); } }; } }; export { c };