From 38f0d922aaa37ee1fa0d775955ce5161f15f61d1 Mon Sep 17 00:00:00 2001 From: SEK1RO Date: Sun, 3 Aug 2025 23:18:27 +0300 Subject: [PATCH] feat(Struct) --- src/ConstArray.js | 47 +++++++++++ src/ConstString.js | 33 ++++++++ src/Struct.js | 93 +++++++++++++++++++++ src/Type.js | 22 +++++ src/index.js | 115 +++++++++++--------------- src/type.js | 18 ---- test/ConstArray.test.js | 34 ++++++++ test/ConstString.test.js | 27 ++++++ test/Struct.test.js | 70 ++++++++++++++++ test/index.test.js | 52 +----------- types/ConstArray.d.ts | 8 ++ types/{type.d.ts => ConstString.d.ts} | 9 +- types/Struct.d.ts | 7 ++ types/Type.d.ts | 1 + types/index.d.ts | 24 +++--- 15 files changed, 410 insertions(+), 150 deletions(-) create mode 100644 src/ConstArray.js create mode 100644 src/ConstString.js create mode 100644 src/Struct.js create mode 100644 src/Type.js delete mode 100644 src/type.js create mode 100644 test/ConstArray.test.js create mode 100644 test/ConstString.test.js create mode 100644 test/Struct.test.js create mode 100644 types/ConstArray.d.ts rename types/{type.d.ts => ConstString.d.ts} (50%) create mode 100644 types/Struct.d.ts create mode 100644 types/Type.d.ts diff --git a/src/ConstArray.js b/src/ConstArray.js new file mode 100644 index 0000000..543dc48 --- /dev/null +++ b/src/ConstArray.js @@ -0,0 +1,47 @@ +import { limits, parse, serialize, sizeofHead, Type } from "." + +export function ConstArray(size) { + const obj = { _size: size } + Object.setPrototypeOf(obj, ConstArray.prototype) + obj.new(ConstArray, arguments) + return obj +} +ConstArray.prototype.serialize = function(dv, src, ...inner_types) { + const item_size = sizeofHead(src[0]) + let size = this._size + + if (dv.byteLength < size * item_size) { + throw new Error('too small buffer') + } + if (size > limits.u32.MAX_VALUE) { + throw new Error('array is too long') + } + + dv.setUint32(0, size) + + for (let i = 0; i < size; i++) { + const item_frame = new DataView(dv.buffer, dv.byteOffset + item_size * i) + serialize(item_frame, src[i], ...inner_types) + } + return +} +ConstArray.prototype.parse = function(dv, ...inner_types) { + const size = this._size + const item_size = sizeofHead(...inner_types) + const array = Array(size) + + for (let i = 0; i < size; i++) { + const item_frame = new DataView(dv.buffer, dv.byteOffset + item_size * i) + array[i] = parse(item_frame, ...inner_types) + } + + return array +} +ConstArray.prototype.isHeadless = function() { + return false +} +ConstArray.prototype.sizeof = function(...inner_types) { + return sizeofHead(...inner_types) * this._size +} +Object.setPrototypeOf(ConstArray.prototype, Type.prototype) +Object.freeze(ConstArray.prototype) diff --git a/src/ConstString.js b/src/ConstString.js new file mode 100644 index 0000000..fa06447 --- /dev/null +++ b/src/ConstString.js @@ -0,0 +1,33 @@ +import { memcpy } from "./mem" +import { Type } from "./Type" + +export function ConstString(size) { + const obj = { _size: size } + Object.setPrototypeOf(obj, ConstString.prototype) + obj.new(ConstString, arguments) + return obj +} +ConstString.prototype.serialize = function(dv, src) { + const encoder = new TextEncoder('utf-8') + const encoded = new DataView(encoder.encode(src).buffer, 0, this._size) + + if (dv.byteLength < encoded.byteLength) { + throw new Error('too small buffer') + } + + memcpy(dv, encoded) + return +} +ConstString.prototype.parse = function(dv) { + const frame = new DataView(dv.buffer, dv.byteOffset, this._size) + const decoder = new TextDecoder('utf-8') + return decoder.decode(frame) +} +ConstString.prototype.isHeadless = function() { + return false +} +ConstString.prototype.sizeof = function() { + return this._size +} +Object.setPrototypeOf(ConstString.prototype, Type.prototype) +Object.freeze(ConstString.prototype) diff --git a/src/Struct.js b/src/Struct.js new file mode 100644 index 0000000..bdf7fe8 --- /dev/null +++ b/src/Struct.js @@ -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) diff --git a/src/Type.js b/src/Type.js new file mode 100644 index 0000000..61330f5 --- /dev/null +++ b/src/Type.js @@ -0,0 +1,22 @@ +export function Type() { + const obj = {} + Object.setPrototypeOf(obj, Type.prototype) + return obj +} +Type.prototype.new = function(func, args) { + this._name = func.name + if (args !== undefined) { + const str_args = Array.from(args).map(arg => JSON.stringify(arg)) + this._name += '(' + str_args.join(', ') + ')' + } +} +Type.prototype.toString = function() { + return this._name +} +Type.prototype.serialize = function() { + throw new Error('should be overloaded') +} +Type.prototype.parse = Type.prototype.serialize +Type.prototype.isHeadless = Type.prototype.serialize +Type.prototype.sizeof = Type.prototype.serialize +Object.freeze(Type.prototype) diff --git a/src/index.js b/src/index.js index 2f8284a..89599c9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,11 @@ import { limits } from "./limits" import { memcpy } from "./mem" -import { ConstArray, ConstString } from "./type" +import { Type } from "./Type" +import { ConstString } from './ConstString' +import { ConstArray } from "./ConstArray" +import { Struct } from './Struct' -export { limits, memcpy, ConstString, ConstArray} +export { limits, memcpy, Type, ConstString, ConstArray, Struct } export function serialize(dv, src, ...types) { const [type, ...inner_types] = types @@ -14,19 +17,12 @@ export function serialize(dv, src, ...types) { dv.setFloat64(0, src) return } - if ((type == String || type._func == ConstString) && typeof src == 'string') { + if (type == String && typeof src == 'string') { const encoder = new TextEncoder('utf-8') - let encoded - if (type == String) { - encoded = new DataView(encoder.encode(src).buffer) - if (dv.byteLength < 4 + encoded.byteLength) { - throw new Error('too small buffer') - } - } else { - encoded = new DataView(encoder.encode(src).buffer, 0, type._size) - if (dv.byteLength < encoded.byteLength) { - throw new Error('too small buffer') - } + let encoded = new DataView(encoder.encode(src).buffer) + + if (dv.byteLength < 4 + encoded.byteLength) { + throw new Error('too small buffer') } if (encoded.byteLength > limits.u32.MAX_VALUE) { throw new Error('string is too long') @@ -38,21 +34,13 @@ export function serialize(dv, src, ...types) { memcpy(frame, encoded) return } - if ((type == Array || type._func == ConstArray) && Array.isArray(src)) { + if (type == Array && Array.isArray(src)) { const item_size = sizeofHead(src[0]) - let size + const size = src.length - if (type == Array) { - size = src.length - if (dv.byteLength < 4 + size * item_size) { - throw new Error('too small buffer') - } - } else { - size = type._size - if (dv.byteLength < size * item_size) { - throw new Error('too small buffer') - } + if (dv.byteLength < 4 + size * item_size) { + throw new Error('too small buffer') } if (size > limits.u32.MAX_VALUE) { throw new Error('array is too long') @@ -61,11 +49,15 @@ export function serialize(dv, src, ...types) { dv.setUint32(0, size) for (let i = 0; i < size; i++) { - const item_frame = new DataView(dv.buffer, dv.byteOffset + item_size * i) + const item_frame = new DataView(dv.buffer, dv.byteOffset + 4 + item_size * i) serialize(item_frame, src[i], ...inner_types) } return } + if (type instanceof Type) { + type.serialize(dv, src, ...inner_types) + return + } } export function parse(dv, ...types) { @@ -74,46 +66,38 @@ export function parse(dv, ...types) { if (type == Number) { return dv.getFloat64(0) } - if (type == String || type._func == ConstString) { - let size - let frame - if (type == String) { - size = dv.getUint32(0) - frame = new DataView(dv.buffer, 4 + dv.byteOffset, size) - } else { - size = type._size - frame = new DataView(dv.buffer, dv.byteOffset, size) - } + if (type == String) { + const size = dv.getUint32(0) + const frame = new DataView(dv.buffer, 4 + dv.byteOffset, size) const decoder = new TextDecoder('utf-8') return decoder.decode(frame) } - if (type == Array || type._func == ConstArray) { - let size - let offset = 0 - if (type == Array) { - size = dv.getUint32(0) - offset = 4 - } else { - size = type._size - } + if (type == Array) { + 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 + offset + item_size * i) + const item_frame = new DataView(dv.buffer, dv.byteOffset + 4 + item_size * i) array[i] = parse(item_frame, ...inner_types) } return array } + if (type instanceof Type) { + return type.parse(dv, ...inner_types) + } } export function isHeadless(...args) { - const [first_arg] = args - return first_arg == Array || - first_arg == String || - Array.isArray(first_arg) || - typeof first_arg == 'string' + const [arg, ...inner_args] = args + if (arg instanceof Type) { + return arg.isHeadless(...inner_args) + } + return arg == Array || + arg == String || + Array.isArray(arg) || + typeof arg == 'string' } export function sizeofHead(...args) { @@ -125,23 +109,24 @@ export function sizeofHead(...args) { } export function sizeof(...args) { - const [first_arg, ...remain_args] = args + const [arg, ...inner_args] = args - if (first_arg == Number || typeof first_arg == 'number') { + if (arg == Number || typeof arg == 'number') { return 8 } - if (first_arg._func == ConstArray) { - return sizeofHead(...remain_args) * first_arg._size - } - if (first_arg._func == ConstString) { - return first_arg._size - } - if (typeof first_arg == 'string') { + if (typeof arg == 'string') { const encoder = new TextEncoder('utf-8') - return 4 + encoder.encode(first_arg).byteLength + return 4 + encoder.encode(arg).byteLength } - if (Array.isArray(first_arg)) { - return 4 + sizeofHead(first_arg[0]) * first_arg.length + if (Array.isArray(arg)) { + return 4 + sizeofHead(arg[0]) * arg.length } - throw new Error('unknown size of ' + args) + 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) } diff --git a/src/type.js b/src/type.js deleted file mode 100644 index 522b124..0000000 --- a/src/type.js +++ /dev/null @@ -1,18 +0,0 @@ -export class Type { - constructor (func, obj) { - this._func = func - Object.assign(this, obj) - } - - toString() { - return this._func.name - } -} - -export function ConstString(size) { - return new Type(ConstString, { _size: size }) -} - -export function ConstArray(size) { - return new Type(ConstArray, { _size: size }) -} diff --git a/test/ConstArray.test.js b/test/ConstArray.test.js new file mode 100644 index 0000000..e3900de --- /dev/null +++ b/test/ConstArray.test.js @@ -0,0 +1,34 @@ +import { describe, expect, test } from "vitest"; +import { ConstArray, parse, serialize, sizeof, sizeofHead } from "../src"; +import { filledDataView, sizedDataView } from "."; + +describe(ConstArray.name, () => { + test('serialize, Number', () => { + const expected = filledDataView([ + 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]) + let dv = sizedDataView(15) + expect(() => serialize(dv, [1, 2], ConstArray(2), Number)).toThrow() + + dv = sizedDataView(sizeof(ConstArray(2), Number)) + expect(16).toEqual(dv.byteLength) + + serialize(dv, [1, 2], ConstArray(2), Number) + expect(dv).toEqual(expected) + }) + + test('parse, Number', () => { + const expected = [1, 2] + const dv = filledDataView([ + 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]) + const actual = parse(dv, ConstArray(2), Number) + expect(actual).toEqual(expected) + }) + + test('sizeof', () => { + expect(sizeofHead(ConstArray(2), Number)).toEqual(16) + }) +}) diff --git a/test/ConstString.test.js b/test/ConstString.test.js new file mode 100644 index 0000000..47abfe9 --- /dev/null +++ b/test/ConstString.test.js @@ -0,0 +1,27 @@ +import { describe, expect, test } from "vitest"; +import { ConstString, parse, serialize, sizeofHead } from "../src"; +import { filledDataView, sizedDataView } from "."; + +describe(ConstString.name, () => { + test('serialize', () => { + const expected = filledDataView([0x68, 0x65, 0x6C, 0x00, 0x00]) + let dv = sizedDataView(4) + expect(() => serialize(dv, 'hello', ConstString(5))).toThrow() + + dv = sizedDataView(5) + + serialize(dv, 'hello', ConstString(3)) + expect(dv).toEqual(expected) + }) + + test('parse', () => { + const expected = 'hel' + const dv = filledDataView([0x68, 0x65, 0x6C, 0x6C, 0x6F]) + const actual = parse(dv, ConstString(3)) + expect(actual).toEqual(expected) + }) + + test('sizeof', () => { + expect(sizeofHead(ConstString(2))).toEqual(2) + }) +}) diff --git a/test/Struct.test.js b/test/Struct.test.js new file mode 100644 index 0000000..cb380e4 --- /dev/null +++ b/test/Struct.test.js @@ -0,0 +1,70 @@ +import { describe, expect, test } from "vitest"; +import { parse, serialize, sizeof, Struct } from "../src"; +import { filledDataView, sizedDataView } from "."; + +describe(Struct.name, () => { + + const User = Struct({ age: Number, name: String }) + const user = { age: 1, name: 'hello' } + const user_dv = filledDataView([ + 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0x05, + 0x68, 0x65, 0x6C, 0x6C, 0x6F, + ]) + + test('serialize, headless', () => { + expect(() => sizeof(User)).toThrow() + + const dv = sizedDataView(sizeof(user, User)) + expect(21).toEqual(dv.byteLength) + + serialize(dv, user, User) + expect(dv).toEqual(user_dv) + }) + + test('parse, headless', () => { + expect(parse(user_dv, User)).toEqual(user) + }) + + const Vector2 = Struct({ x: Number, y: Number }) + const vector2 = { x: 1, y: 2 } + const vector2_dv = filledDataView([ + 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]) + + test('serialize, non-headless', () => { + const dv = sizedDataView(sizeof(Vector2)) + expect(16).toEqual(dv.byteLength) + + serialize(dv, vector2, Vector2) + expect(dv).toEqual(vector2_dv) + }) + + test('parse, non-headless', () => { + expect(parse(vector2_dv, Vector2)).toEqual(vector2) + }) + + const Nested = Struct({ user: User, vector2: [Vector2] }) + const nested = { user, vector2 } + const nested_dv = filledDataView([ + 0x00, 0x00, 0x00, 0x14, + 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0x05, + 0x68, 0x65, 0x6C, 0x6C, 0x6F, + ]) + + test('serialize, nested', () => { + const dv = sizedDataView(sizeof(nested, Nested)) + serialize(dv, nested, Nested) + expect(dv).toEqual(nested_dv) + }) + + test('parse, nested', () => { + expect(parse(nested_dv, Nested)).toEqual(nested) + }) +}) diff --git a/test/index.test.js b/test/index.test.js index cc115aa..0994429 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,7 +1,6 @@ import { describe, test, expect } from 'vitest' import { filledDataView, sizedDataView } from '.' import { parse, serialize, sizeof, sizeofHead } from '../src' -import { ConstArray, ConstString } from '../src/type' describe('serialize', () => { test('Number', () => { @@ -15,16 +14,6 @@ describe('serialize', () => { serialize(dv, 1532.625, Number) expect(dv).toEqual(expected) }) - test('ConstString', () => { - const expected = filledDataView([0x68, 0x65, 0x6C, 0x00, 0x00]) - let dv = sizedDataView(4) - expect(() => serialize(dv, 'hello', ConstString(5))).toThrow() - - dv = sizedDataView(5) - - serialize(dv, 'hello', ConstString(3)) - expect(dv).toEqual(expected) - }) test('String', () => { const expected = filledDataView([ 0x00, 0x00, 0x00, 0x05, @@ -39,20 +28,6 @@ describe('serialize', () => { serialize(dv, 'hello', String) expect(dv).toEqual(expected) }) - test('ConstArray, Number', () => { - const expected = filledDataView([ - 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]) - let dv = sizedDataView(15) - expect(() => serialize(dv, [1, 2], ConstArray(2), Number)).toThrow() - - dv = sizedDataView(sizeof(ConstArray(2), Number)) - expect(16).toEqual(dv.byteLength) - - serialize(dv, [1, 2], ConstArray(2), Number) - expect(dv).toEqual(expected) - }) test('Array, Number', () => { const expected = filledDataView([ 0x00, 0x00, 0x00, 0x02, @@ -77,12 +52,6 @@ describe('parse', () => { const actual = parse(dv, Number) expect(actual).toEqual(expected) }) - test('ConstString', () => { - const expected = 'hel' - const dv = filledDataView([0x68, 0x65, 0x6C, 0x6C, 0x6F]) - const actual = parse(dv, ConstString(3)) - expect(actual).toEqual(expected) - }) test('String', () => { const expected = 'hello' const dv = filledDataView([ @@ -92,15 +61,6 @@ describe('parse', () => { const actual = parse(dv, String) expect(actual).toEqual(expected) }) - test('ConstArray, Number', () => { - const expected = [1, 2] - const dv = filledDataView([ - 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]) - const actual = parse(dv, ConstArray(2), Number) - expect(actual).toEqual(expected) - }) test('Array, Number', () => { const expected = [1, 2] const dv = filledDataView([ @@ -116,21 +76,15 @@ describe('parse', () => { describe('sizeofHead', () => { test('Number', () => { expect(sizeofHead(Number)).toEqual(8) - expect(sizeofHead(1)).toEqual(8) - }) - test('ConstString', () => { - expect(sizeofHead(ConstString(2))).toEqual(2) + expect(sizeofHead(1, Number)).toEqual(8) }) test('String', () => { expect(sizeofHead(String)).toEqual(4) - expect(sizeofHead('s')).toEqual(4) - }) - test('ConstArray', () => { - expect(sizeofHead(ConstArray(2), Number)).toEqual(16) + expect(sizeofHead('s', String)).toEqual(4) }) test('Array', () => { expect(sizeofHead(Array, Number)).toEqual(4) - expect(sizeofHead([1])).toEqual(4) + expect(sizeofHead([1], Array, Number)).toEqual(4) }) }) diff --git a/types/ConstArray.d.ts b/types/ConstArray.d.ts new file mode 100644 index 0000000..b624515 --- /dev/null +++ b/types/ConstArray.d.ts @@ -0,0 +1,8 @@ +import { Type } from "."; + +/** + * constructs type of array with constant byte size + * @param {number} size number of items + * @returns {Type} + */ +export function ConstArray(size: number): Type; diff --git a/types/type.d.ts b/types/ConstString.d.ts similarity index 50% rename from types/type.d.ts rename to types/ConstString.d.ts index 2047810..02291af 100644 --- a/types/type.d.ts +++ b/types/ConstString.d.ts @@ -1,4 +1,4 @@ -export type Type = unknown +import { Type } from "."; /** * constructs type of utf8-string with constant byte size @@ -6,10 +6,3 @@ export type Type = unknown * @returns {Type} */ export function ConstString(byte_size: number): Type; - -/** - * constructs type of array with constant byte size - * @param {number} size number of items - * @returns {Type} - */ -export function ConstArray(size: number): Type; diff --git a/types/Struct.d.ts b/types/Struct.d.ts new file mode 100644 index 0000000..977f317 --- /dev/null +++ b/types/Struct.d.ts @@ -0,0 +1,7 @@ +import { SerializableType, Type } from "." + +/** + * constructs type of c-like structure. if field is headless, inside of structure will be stored u32 offset, outside of structure will be stored value of field + * @returns {Type} + */ +export function Struct(type_obj: Record): Type; diff --git a/types/Type.d.ts b/types/Type.d.ts new file mode 100644 index 0000000..c507c44 --- /dev/null +++ b/types/Type.d.ts @@ -0,0 +1 @@ +export type Type = unknown diff --git a/types/index.d.ts b/types/index.d.ts index f86770e..140d393 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,10 +1,11 @@ import { memcpy } from "./mem"; import { limits } from "./limits"; -import { ConstString, ConstArray } from "./type"; +import { Type } from "./Type" +import { ConstString } from "./ConstString" +import { ConstArray } from "./ConstArray"; +import { Struct } from "./Struct"; -export { memcpy, limits, ConstString, ConstArray } - -import { Type } from "./type"; +export { memcpy, limits, Type, ConstString, ConstArray, Struct } export type SerializableType = NumberConstructor | StringConstructor | ArrayConstructor | Type export type Serializable = number | string | array @@ -28,13 +29,14 @@ export function parse(dv: DataView, ...types: SerializableType[]): Serializable; /** * some types, like Array, String, has no fixed size. So in Structure they are stored as u32 offset, which points to their beginning * @param {Serializable} obj to check + * @param {SerializableType[]} ...types primary and inner types. eg: Array, Number * @returns {boolean} */ -export function isHeadless(obj: Serializable): boolean; +export function isHeadless(obj: Serializable, ...types: SerializableType[]): boolean; /** * some types, like Array, String, has no fixed size. So in Structure they are stored as u32 offset, which points to their beginning - * @param {SerializableType[]} ...args primary and inner types. eg: Array, Number + * @param {SerializableType[]} ...types primary and inner types. eg: Array, Number * @returns {boolean} */ export function isHeadless(...types: SerializableType[]): boolean; @@ -42,25 +44,27 @@ export function isHeadless(...types: SerializableType[]): boolean; /** * if obj has no fixed size, return 4 (sizeof u32 offset) * @param {Serializable} obj to check + * @param {SerializableType[]} ...types primary and inner types. eg: Array, Number * @returns {number} */ -export function sizeofHead(obj: Serializable): number; +export function sizeofHead(obj: Serializable, ...types: SerializableType[]): number; /** * if obj has no fixed size, return 4 (sizeof u32 offset) - * @param {SerializableType[]} ...args primary and inner types. eg: Array, Number + * @param {SerializableType[]} ...types primary and inner types. eg: Array, Number * @returns {number} */ export function sizeofHead(...types: SerializableType[]): number; /** * @param {Serializable} obj to check + * @param {SerializableType[]} ...types primary and inner types. eg: Array, Number * @returns {number} */ -export function sizeof(obj: Serializable): number; +export function sizeof(obj: Serializable, ...types: SerializableType[]): number; /** - * @param {SerializableType[]} ...args primary and inner types. eg: Array, Number + * @param {SerializableType[]} ...types primary and inner types. eg: Array, Number * @returns {number} * @throws {Error} if passed Array or String type (unknown sizeof) */