feat(Struct)
This commit is contained in:
93
src/Struct.js
Normal file
93
src/Struct.js
Normal 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)
|
||||
Reference in New Issue
Block a user