import { isHeadless, parse, serialize, sizeof, sizeofHead, Type } from "." export function Struct(type_obj) { const obj = {} Object.setPrototypeOf(obj, Struct.prototype) obj._info_by_key = new Map obj._headless = false const arg = {} let offset = 0 for (const [key, value] of Object.entries(type_obj)) { let types if (Array.isArray(value)) { types = value } else { types = [value] } arg[key] = types.map(type => type.name) const headless = isHeadless(...types) obj._info_by_key.set(key, { offset, types, headless, }) obj._headless |= headless offset += sizeofHead(...types) } obj._size = offset obj.new(Struct, [arg]) return obj } Struct.prototype.serialize = function(dv, src) { let data_offset = this._size for (const [key, value] of Object.entries(src)) { const info = this._info_by_key.get(key) if (info.headless) { dv.setUint32(info.offset, data_offset) const frame = new DataView(dv.buffer, dv.byteOffset + data_offset) serialize(frame, value, ...info.types) data_offset += sizeof(value, ...info.types) } else { const frame = new DataView(dv.buffer, dv.byteOffset + info.offset) serialize(frame, value, ...info.types) } } } Struct.prototype.parse = function(dv) { const res = {} for (const [key, info] of this._info_by_key.entries()) { if (info.headless) { const data_offset = dv.getUint32(info.offset) const frame = new DataView(dv.buffer, dv.byteOffset + data_offset) res[key] = parse(frame, ...info.types) } else { const frame = new DataView(dv.buffer, dv.byteOffset + info.offset) res[key] = parse(frame, ...info.types) } } return res } Struct.prototype.isHeadless = function() { return this._headless } Struct.prototype.sizeof = function(arg) { if (this._headless) { if (arg === undefined) { throw new Error('unknown size of ' + this) } let size = this._size for (const [key, info] of this._info_by_key.entries()) { if (info.headless) { size += sizeof(arg[key], ...info.types) } } return size } else { return this._size } } Object.setPrototypeOf(Struct.prototype, Type.prototype) Object.freeze(Struct.prototype)