fix(Array, {HeadlessType})

This commit is contained in:
2025-08-06 16:20:14 +03:00
parent 35a98456ef
commit 16789a942e
12 changed files with 246 additions and 74 deletions

View File

@ -14,14 +14,14 @@ export function serialize(dv, src, ...types) {
if (type == Boolean && typeof src == 'boolean') {
if (dv.byteLength < 1) {
throw new Error('too small buffer')
throw new Error('Boolean too small buffer')
}
dv.setUint8(0, src ? 1 : 0)
return
}
if (type == Number && typeof src == 'number') {
if (dv.byteLength < 8) {
throw new Error('too small buffer')
throw new Error('Number too small buffer')
}
dv.setFloat64(0, src)
return
@ -31,10 +31,10 @@ export function serialize(dv, src, ...types) {
let encoded = new DataView(encoder.encode(src).buffer)
if (dv.byteLength < 4 + encoded.byteLength) {
throw new Error('too small buffer')
throw new Error('String too small buffer')
}
if (encoded.byteLength > limits.u32.MAX_VALUE) {
throw new Error('string is too long')
throw new Error('String is too long')
}
dv.setUint32(0, encoded.byteLength)
@ -44,31 +44,40 @@ export function serialize(dv, src, ...types) {
return
}
if (type == Array && Array.isArray(src)) {
const item_size = sizeofHead(src[0])
const item_headless = isHeadless(...inner_types)
const item_head_size = sizeofHead(...inner_types)
const size = src.length
if (dv.byteLength < 4 + size * item_size) {
throw new Error('too small buffer')
if (dv.byteLength < sizeof(src, ...types)) {
throw new Error('Array, ' + inner_types.join(', ') + ' too small buffer')
}
if (size > limits.u32.MAX_VALUE) {
throw new Error('array is too long')
throw new Error('Array, ' + inner_types.join(', ') + ' is too long')
}
dv.setUint32(0, size)
let offset = 4 + item_head_size * size
for (let i = 0; i < size; i++) {
const item_frame = new DataView(dv.buffer, dv.byteOffset + 4 + item_size * i)
serialize(item_frame, src[i], ...inner_types)
const item_head_frame = new DataView(dv.buffer, dv.byteOffset + 4 + item_head_size * i)
if (item_headless) {
item_head_frame.setUint32(0, offset)
const item_frame = new DataView(dv.buffer, dv.byteOffset + offset)
serialize(item_frame, src[i], ...inner_types)
offset += sizeof(src[i], ...inner_types)
} else {
serialize(item_head_frame, src[i], ...inner_types)
}
}
return
}
if (type == DataView && src instanceof DataView) {
if (dv.byteLength < 4 + src.byteLength) {
throw new Error('too small buffer')
throw new Error('DataView too small buffer')
}
if (src.byteLength > limits.u32.MAX_VALUE) {
throw new Error('data view is too long')
throw new Error('DataView data is too long')
}
dv.setUint32(0, src.byteLength)
@ -99,13 +108,20 @@ export function parse(dv, ...types) {
return decoder.decode(frame)
}
if (type == Array) {
const item_headless = isHeadless(...inner_types)
const item_head_size = sizeofHead(...inner_types)
const size = dv.getUint32(0)
const item_size = sizeofHead(inner_types[0])
const array = Array(size)
for (let i = 0; i < size; i++) {
const item_frame = new DataView(dv.buffer, dv.byteOffset + 4 + item_size * i)
array[i] = parse(item_frame, ...inner_types)
const item_head_frame = new DataView(dv.buffer, dv.byteOffset + 4 + item_head_size * i)
if (item_headless) {
const offset = item_head_frame.getUint32(0)
const item_frame = new DataView(dv.buffer, dv.byteOffset + offset)
array[i] = parse(item_frame, ...inner_types)
} else {
array[i] = parse(item_head_frame, ...inner_types)
}
}
return array
@ -148,29 +164,50 @@ export function sizeofHead(...args) {
export function sizeof(...args) {
const [arg, ...inner_args] = args
const [arg2, ...inner_args2] = inner_args
if (arg == Boolean || typeof arg == 'boolean') {
if (arg == Boolean || arg2 == Boolean && typeof arg == 'boolean') {
return 1
}
if (arg == Number || typeof arg == 'number') {
if (arg == Number || arg2 == Number && typeof arg == 'number') {
return 8
}
if (typeof arg == 'string') {
if (arg2 == String && typeof arg == 'string') {
const encoder = new TextEncoder('utf-8')
return 4 + encoder.encode(arg).byteLength
}
if (Array.isArray(arg)) {
return 4 + sizeofHead(arg[0]) * arg.length
if (arg2 == Array && Array.isArray(arg)) {
const fixed_size = 4 + sizeofHead(...inner_args2) * arg.length
if (isHeadless(...inner_args2)) {
let variable_size = 0
for (const item of arg) {
variable_size += sizeof(item, ...inner_args2)
}
return fixed_size + variable_size
} else {
return fixed_size
}
}
if (arg instanceof DataView) {
if (arg2 == DataView && arg instanceof DataView) {
return 4 + arg.byteLength
}
if (arg instanceof Type) {
return arg.sizeof(...inner_args)
}
const [arg2, ...inner_args2] = inner_args
if (arg2 instanceof Type) {
return arg2.sizeof(arg, ...inner_args2)
}
throw new Error('unknown size of ' + arg)
throw new Error('unknown size of ' + args)
}
export function isSerializableType(type) {
return type == Boolean ||
type == Number ||
type == String ||
type == Array ||
type == DataView ||
type instanceof Type
}