fix(Array, {HeadlessType})
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { parse, serialize, sizeofHead, Type } from "."
|
||||
import { isHeadless, isSerializableType, parse, serialize, sizeof, sizeofHead, Type } from "."
|
||||
|
||||
export function ConstArray(size) {
|
||||
const obj = { _size: size }
|
||||
@ -7,39 +7,82 @@ export function ConstArray(size) {
|
||||
return obj
|
||||
}
|
||||
ConstArray.prototype.serialize = function(dv, src, ...inner_types) {
|
||||
const item_size = sizeofHead(src[0])
|
||||
const item_headless = isHeadless(...inner_types)
|
||||
const item_head_size = sizeofHead(src[0], ...inner_types)
|
||||
const size = this._size
|
||||
|
||||
if (dv.byteLength < size * item_size) {
|
||||
throw new Error('too small buffer')
|
||||
if (dv.byteLength < this.sizeof(src, ...inner_types)) {
|
||||
throw new Error(this.name_+ ', ' + inner_types.join(', ') + ' too small buffer')
|
||||
}
|
||||
if (src.length != size) {
|
||||
throw new Error('array should be ' + size + ' elements length')
|
||||
throw new Error(this.name_+ ', ' + inner_types.join(', ') + ' should be ' + size + ' elements length')
|
||||
}
|
||||
|
||||
let offset = item_head_size * 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)
|
||||
const item_head_frame = new DataView(dv.buffer, dv.byteOffset + 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
|
||||
}
|
||||
ConstArray.prototype.parse = function(dv, ...inner_types) {
|
||||
ConstArray.prototype.parse = function(dv, ...inner_types) {
|
||||
const item_headless = isHeadless(...inner_types)
|
||||
const item_head_size = sizeofHead(...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)
|
||||
const item_head_frame = new DataView(dv.buffer, dv.byteOffset + 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
|
||||
}
|
||||
ConstArray.prototype.isHeadless = function() {
|
||||
return false
|
||||
ConstArray.prototype.isHeadless = function(...inner_types) {
|
||||
return isHeadless(...inner_types)
|
||||
}
|
||||
ConstArray.prototype.sizeof = function(...inner_types) {
|
||||
return sizeofHead(...inner_types) * this._size
|
||||
ConstArray.prototype.sizeof = function(arg, ...args) {
|
||||
let inner_types
|
||||
let src
|
||||
|
||||
if (isSerializableType(arg)) {
|
||||
src = undefined
|
||||
inner_types = [arg, ...args]
|
||||
} else {
|
||||
src = arg
|
||||
inner_types = args
|
||||
}
|
||||
|
||||
const fixed_size = sizeofHead(...inner_types) * this._size
|
||||
|
||||
if (isHeadless(...inner_types)) {
|
||||
if (src == undefined) {
|
||||
throw new Error('unknown sizeof ' + this._name + ', ' + inner_types.join(','))
|
||||
}
|
||||
|
||||
let variable_size = 0
|
||||
for (const item of src) {
|
||||
variable_size += sizeof(item, ...inner_types)
|
||||
}
|
||||
|
||||
return fixed_size + variable_size
|
||||
} else {
|
||||
return fixed_size
|
||||
}
|
||||
}
|
||||
Object.setPrototypeOf(ConstArray.prototype, Type.prototype)
|
||||
Object.freeze(ConstArray.prototype)
|
||||
|
||||
@ -8,10 +8,10 @@ export function ConstDataView(size) {
|
||||
}
|
||||
ConstDataView.prototype.serialize = function(dv, src) {
|
||||
if (dv.byteLength < this._size) {
|
||||
throw new Error('too small buffer')
|
||||
throw new Error(this._name + ' too small buffer')
|
||||
}
|
||||
if (src.byteLength != this._size) {
|
||||
throw new Error('buffer should be ' + this._size + ' bytes length')
|
||||
throw new Error(this._name + ' should be ' + this._size + ' bytes length')
|
||||
}
|
||||
memcpy(dv, src)
|
||||
return
|
||||
|
||||
@ -12,10 +12,10 @@ ConstString.prototype.serialize = function(dv, src) {
|
||||
const encoded = new DataView(encoder.encode(src).buffer, 0, this._size)
|
||||
|
||||
if (dv.byteLength < encoded.byteLength) {
|
||||
throw new Error('too small buffer')
|
||||
throw new Error(this._name + ' too small buffer')
|
||||
}
|
||||
if (src.length != this._size) {
|
||||
throw new Error('string should be ' + this._size + ' symbols length')
|
||||
throw new Error(this._name + ' should be ' + this._size + ' symbols length')
|
||||
}
|
||||
|
||||
memcpy(dv, encoded)
|
||||
|
||||
12
src/Int.js
12
src/Int.js
@ -27,7 +27,7 @@ export function Int(bits, sign) {
|
||||
break
|
||||
|
||||
default:
|
||||
throw new Error('incorrect bits ' + bits)
|
||||
throw new Error(obj._name + ' incorrect bits ' + bits)
|
||||
}
|
||||
break
|
||||
|
||||
@ -52,25 +52,25 @@ export function Int(bits, sign) {
|
||||
break
|
||||
|
||||
default:
|
||||
throw new Error('incorrect bits ' + bits)
|
||||
throw new Error(obj._name + ' incorrect bits ' + bits)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
throw new Error('incorrect sign ' + sign)
|
||||
throw new Error(obj._name + ' incorrect sign ' + sign)
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
Int.prototype.serialize = function (dv, src) {
|
||||
if (dv.byteLength < this._size) {
|
||||
throw new Error('buffer is too small')
|
||||
throw new Error(this._name + ' buffer is too small')
|
||||
}
|
||||
if (src > this._limits.MAX_VALUE) {
|
||||
throw new Error(`number should be less or equal than ` + this._limits.MAX_VALUE)
|
||||
throw new Error(this._name + ` should be less or equal than ` + this._limits.MAX_VALUE)
|
||||
}
|
||||
if (src < this._limits.MIN_VALUE) {
|
||||
throw new Error(`number should be more or equal than ` + this._limits.MIN_VALUE)
|
||||
throw new Error(this._name + ` should be more or equal than ` + this._limits.MIN_VALUE)
|
||||
}
|
||||
this._dv_set.call(dv, 0, src)
|
||||
}
|
||||
|
||||
85
src/index.js
85
src/index.js
@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user