feat(Sequence)

This commit is contained in:
2025-08-08 11:28:49 +03:00
parent ebe15d2d05
commit c5c0c17db2
6 changed files with 153 additions and 1 deletions

91
src/Sequence.js Normal file
View File

@ -0,0 +1,91 @@
import { isHeadless, parse, serialize, sizeof } from '.'
import { Type } from './Type'
export function Sequence(types) {
const obj = { _types: types, _headless: false, _sizeof: 0 }
Object.setPrototypeOf(obj, Sequence.prototype)
obj.new(Sequence, [
types.map((arg) => {
if (typeof arg == 'function') {
return arg.name
} else {
return arg
}
}),
])
for (let i = 0; i < types.length; i++) {
if (!Array.isArray(types[i])) {
types[i] = [types[i]]
}
obj._headless |= isHeadless(...types[i])
if (obj._headless) {
obj._sizeof = null
} else {
obj._sizeof += sizeof(...types[i])
}
}
return obj
}
Sequence.prototype._srcValidate = function (src) {
if (!Array.isArray(src) || src.length != this._types.length) {
throw new Error(
this._name +
' source object should be array with length ' +
this._types.length,
)
}
}
Sequence.prototype.serialize = function (dv, src) {
if (dv.byteLength < this.sizeof(src)) {
throw new Error(this._name + ' too small buffer')
}
this._srcValidate(src)
let offset = 0
for (let i = 0; i < src.length; i++) {
const item = src[i]
const item_types = this._types[i]
const item_frame = new DataView(dv.buffer, dv.byteOffset + offset)
serialize(item_frame, item, ...item_types)
offset += sizeof(item, ...item_types)
}
}
Sequence.prototype.parse = function (dv) {
const res = new Array(this._types.length)
let offset = 0
for (let i = 0; i < res.length; i++) {
const item_types = this._types[i]
const item_frame = new DataView(dv.buffer, dv.byteOffset + offset)
res[i] = parse(item_frame, ...item_types)
offset += sizeof(res[i], ...item_types)
}
return res
}
Sequence.prototype.isHeadless = function () {
return this._headless
}
Sequence.prototype.sizeof = function (src) {
if (this._headless) {
if (src == undefined) {
throw new Error('unknown sizeof ' + this._name)
}
this._srcValidate(src)
let size = 0
for (let i = 0; i < src.length; i++) {
const item = src[i]
const item_types = this._types[i]
size += sizeof(item, ...item_types)
}
return size
} else {
return this._sizeof
}
}
Object.setPrototypeOf(Sequence.prototype, Type.prototype)
Object.freeze(Sequence.prototype)

View File

@ -6,13 +6,20 @@ export function Type() {
Type.prototype.new = function (func, args) {
this._name = func.name
if (args !== undefined) {
const str_args = Array.from(args).map((arg) => JSON.stringify(arg))
const str_args = Array.from(args).map((arg) => {
if (typeof arg == 'function') {
return arg.name
} else {
return JSON.stringify(arg)
}
})
this._name += '(' + str_args.join(', ') + ')'
}
}
Type.prototype.toString = function () {
return this._name
}
Type.prototype.toJSON = Type.prototype.toString
Type.prototype.serialize = function () {
throw new Error('should be overloaded')
}

View File

@ -5,6 +5,7 @@ import { Int } from './Int'
import { ConstString } from './ConstString'
import { ConstArray } from './ConstArray'
import { ConstDataView } from './ConstDataView'
import { Sequence } from './Sequence'
import { Struct } from './Struct'
export {
@ -15,6 +16,7 @@ export {
ConstString,
ConstArray,
ConstDataView,
Sequence,
Struct,
}