feat(Struct)

This commit is contained in:
2025-08-03 23:18:27 +03:00
parent 72f287a4e4
commit 38f0d922aa
15 changed files with 410 additions and 150 deletions

93
src/Struct.js Normal file
View File

@ -0,0 +1,93 @@
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)