Compare commits
2 Commits
f785493ec2
...
cdd6564b51
Author | SHA1 | Date | |
---|---|---|---|
cdd6564b51 | |||
9bc48fc0c0 |
@ -1,6 +1,6 @@
|
||||
import { BaseTypeHandler, CompoundTypeHandler } from './type-handler.mjs';
|
||||
|
||||
export { BASIC_TYPES, FixedArrayHandler, DynamicArrayHandler, CompoundTypeHandler } from './type-handler.mjs';
|
||||
export { BASIC_TYPES } from './type-handler.mjs';
|
||||
|
||||
/**
|
||||
* Serializes JavaScript value to binary.
|
||||
|
@ -4,7 +4,8 @@
|
||||
"main": "index.mjs",
|
||||
"dependencies": {
|
||||
"@og/error-utils": "file:../error-utils",
|
||||
"@og/utility": "file:../utility",
|
||||
"@og/uuid": "file:../uuid",
|
||||
"@og/utility": "file:../utility"
|
||||
"buffer": "^6.0.3"
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { BASIC_TYPES, FixedArrayHandler, DynamicArrayHandler, CompoundTypeHandler, serializeToBinary, deserializeFromBinary } from '../index.mjs';
|
||||
import { BASIC_TYPES, serializeToBinary, deserializeFromBinary } from '../index.mjs';
|
||||
import assert from 'node:assert/strict';
|
||||
import { areArrayBuffersEqual } from '@og/utility';
|
||||
import { UUID } from '@og/uuid';
|
||||
@ -82,13 +82,13 @@ describe('binary-struct', () => {
|
||||
});
|
||||
|
||||
it('type u16[]', () => {
|
||||
let res = serializeToBinary([0x1770, 0x3c3a, 0x9012], new DynamicArrayHandler(BASIC_TYPES.u16));
|
||||
let res = serializeToBinary([0x1770, 0x3c3a, 0x9012], BASIC_TYPES.array(BASIC_TYPES.u16));
|
||||
let ans = new Uint8Array([0x03, 0x00, 0x00, 0x00, 0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]);
|
||||
assert.ok(areArrayBuffersEqual(res, ans));
|
||||
});
|
||||
|
||||
it('type u16[3]', () => {
|
||||
let res = serializeToBinary([0x1770, 0x3c3a, 0x9012], new FixedArrayHandler(3, BASIC_TYPES.u16));
|
||||
let res = serializeToBinary([0x1770, 0x3c3a, 0x9012], BASIC_TYPES.FixedArray(3, BASIC_TYPES.u16));
|
||||
let ans = new Uint8Array([0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]);
|
||||
assert.ok(areArrayBuffersEqual(res, ans));
|
||||
});
|
||||
@ -104,6 +104,18 @@ describe('binary-struct', () => {
|
||||
let ans = new Uint8Array([0x80, 0x30, 0x18, 0x46, 0, 0, 0, 0]);
|
||||
assert.ok(areArrayBuffersEqual(res, ans));
|
||||
});
|
||||
|
||||
it('type Buffer', () => {
|
||||
let ans = new Uint8Array([0x3c, 0x3d, 0x3e, 0x3f]).buffer;
|
||||
let res = serializeToBinary(Buffer.from(ans), BASIC_TYPES.raw(4));
|
||||
assert.ok(areArrayBuffersEqual(res, ans));
|
||||
});
|
||||
|
||||
it('type StringMap', () => {
|
||||
let res = serializeToBinary(new Map([['aa', 'b'], ['hi', 'hello']]), BASIC_TYPES.StringMap);
|
||||
let ans = new Uint8Array([0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x61, 0x61, 0x01, 0x00, 0x00, 0x00, 0x62, 0x02, 0x00, 0x00, 0x00, 0x68, 0x69, 0x05, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f]).buffer;
|
||||
assert.ok(areArrayBuffersEqual(res, ans));
|
||||
});
|
||||
});
|
||||
|
||||
describe('deserializeFromBinary', () => {
|
||||
@ -179,14 +191,14 @@ describe('binary-struct', () => {
|
||||
|
||||
it('type u16[]', () => {
|
||||
let binary_data = new Uint8Array([0x03, 0x00, 0x00, 0x00, 0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]).buffer;
|
||||
let res = deserializeFromBinary(new DataView(binary_data), new DynamicArrayHandler(BASIC_TYPES.u16));
|
||||
let res = deserializeFromBinary(new DataView(binary_data), BASIC_TYPES.array(BASIC_TYPES.u16));
|
||||
let ans = [0x1770, 0x3c3a, 0x9012];
|
||||
assert.deepEqual(res, ans);
|
||||
});
|
||||
|
||||
it('type u16[3]', () => {
|
||||
let binary_data = new Uint8Array([0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]).buffer;
|
||||
let res = deserializeFromBinary(new DataView(binary_data), new FixedArrayHandler(3, BASIC_TYPES.u16));
|
||||
let res = deserializeFromBinary(new DataView(binary_data), BASIC_TYPES.FixedArray(3, BASIC_TYPES.u16));
|
||||
let ans = [0x1770, 0x3c3a, 0x9012];
|
||||
assert.deepEqual(res, ans);
|
||||
});
|
||||
@ -206,5 +218,18 @@ describe('binary-struct', () => {
|
||||
let ans = new Date("2007-04-08");
|
||||
assert.equal(ans.toUTCString(), res.toUTCString());
|
||||
});
|
||||
|
||||
it('type Buffer', () => {
|
||||
let binary_data = new Uint8Array([0x3c, 0x3d, 0x3e, 0x3f]).buffer;
|
||||
let res = deserializeFromBinary(new DataView(binary_data), BASIC_TYPES.raw(4));
|
||||
assert.deepEqual(Buffer.from(binary_data), res);
|
||||
});
|
||||
|
||||
it('type StringMap', () => {
|
||||
let binary_data = new Uint8Array([0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x61, 0x61, 0x01, 0x00, 0x00, 0x00, 0x62, 0x02, 0x00, 0x00, 0x00, 0x68, 0x69, 0x05, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f]).buffer;
|
||||
let res = deserializeFromBinary(new DataView(binary_data), BASIC_TYPES.StringMap);
|
||||
let ans = new Map([['aa', 'b'], ['hi', 'hello']]);
|
||||
assert.deepEqual(res, ans);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { VirtualMethodNotImplementedError } from '@og/error-utils';
|
||||
import { UUID } from '@og/uuid';
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
/**
|
||||
* Represents the result of deserialization.
|
||||
@ -551,6 +552,13 @@ export class VoidHandler extends BaseTypeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
function getHandlerObject(type) {
|
||||
if (type instanceof BaseTypeHandler) {
|
||||
return type;
|
||||
}
|
||||
return new CompoundTypeHandler(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles array of a fixed length with elements of the same type.
|
||||
* @extends {BaseTypeHandler}
|
||||
@ -565,7 +573,7 @@ export class FixedArrayHandler extends BaseTypeHandler {
|
||||
constructor(n, element_handler) {
|
||||
super();
|
||||
this.n = n;
|
||||
this.element_handler = element_handler;
|
||||
this.element_handler = getHandlerObject(element_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -612,6 +620,56 @@ export class FixedArrayHandler extends BaseTypeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles raw binary buffer of a fixed length.
|
||||
* @extends {BaseTypeHandler}
|
||||
* @class
|
||||
*/
|
||||
export class RawBufferHandler extends BaseTypeHandler {
|
||||
/**
|
||||
* Constructor for RawBufferHandler.
|
||||
* @param {number} n - The fixed length of the buffer.
|
||||
*/
|
||||
constructor(n) {
|
||||
super();
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the serialized fixed-length buffer in bytes.
|
||||
* @param {Buffer} value - The array to calculate the size for.
|
||||
* @returns {number} - The size of the serialized fixed-length array in bytes.
|
||||
*/
|
||||
sizeof(value) {
|
||||
return value.byteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the fixed-length buffer and writes it to the DataView at the specified offset.
|
||||
* @param {DataView} view - The DataView to write to.
|
||||
* @param {number} offset - The offset to start writing at.
|
||||
* @param {Buffer} value - The fixed-length buffer to be serialized.
|
||||
* @returns {number} - The new offset after serialization.
|
||||
*/
|
||||
serialize(view, offset, value) {
|
||||
for (let i = 0; i < this.n; i += 1) {
|
||||
view.setUint8(offset + i, value.readUInt8(offset + i));
|
||||
}
|
||||
return offset + this.n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the fixed-length array from the DataView at the specified offset.
|
||||
* @param {DataView} view - The DataView to read from.
|
||||
* @param {number} offset - The offset to start reading from.
|
||||
* @returns {DeserializedResult} - The deserialized result containing the fixed-length array and a new offset.
|
||||
*/
|
||||
deserialize(view, offset) {
|
||||
const res = Buffer.from(view.buffer, offset, this.n);
|
||||
return new DeserializedResult(res, offset + this.n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles dynamic arrays with elements of the same type.
|
||||
* @extends {BaseTypeHandler}
|
||||
@ -624,7 +682,7 @@ export class DynamicArrayHandler extends BaseTypeHandler {
|
||||
*/
|
||||
constructor(element_handler) {
|
||||
super();
|
||||
this.element_handler = element_handler;
|
||||
this.element_handler = getHandlerObject(element_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -675,6 +733,74 @@ export class DynamicArrayHandler extends BaseTypeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles map with keys and values are of the same type.
|
||||
* @extends {BaseTypeHandler}
|
||||
* @class
|
||||
*/
|
||||
export class MapHandler extends BaseTypeHandler {
|
||||
/**
|
||||
* Constructor for MapHandler.
|
||||
* @param {BaseTypeHandler} key_handler - The handler for keys of the map.
|
||||
* @param {BaseTypeHandler} value_handler - The handler for values of the map.
|
||||
*/
|
||||
constructor(key_handler, value_handler) {
|
||||
super();
|
||||
this.key_handler = getHandlerObject(key_handler);
|
||||
this.value_handler = getHandlerObject(value_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the serialized map in bytes.
|
||||
* @param {Map} value - The map to calculate the size for.
|
||||
* @returns {number} - The size of the serialized map in bytes.
|
||||
*/
|
||||
sizeof(value) {
|
||||
let res = 4;
|
||||
for (const [k, v] of value) {
|
||||
res += this.key_handler.sizeof(k);
|
||||
res += this.value_handler.sizeof(v);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the map and writes it to the DataView at the specified offset.
|
||||
* @param {DataView} view - The DataView to write to.
|
||||
* @param {number} offset - The offset to start writing at.
|
||||
* @param {Map} value - The map to be serialized.
|
||||
* @returns {number} - The new offset after serialization.
|
||||
*/
|
||||
serialize(view, offset, value) {
|
||||
view.setUint32(offset, value.size, true);
|
||||
offset += 4;
|
||||
for (const [k, v] of value) {
|
||||
offset = this.key_handler.serialize(view, offset, k);
|
||||
offset = this.value_handler.serialize(view, offset, v);
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the map from the DataView at the specified offset.
|
||||
* @param {DataView} view - The DataView to read from.
|
||||
* @param {number} offset - The offset to start reading from.
|
||||
* @returns {DeserializedResult} - The deserialized result containing the map and a new offset.
|
||||
*/
|
||||
deserialize(view, offset) {
|
||||
const size = view.getUint32(offset, true);
|
||||
offset += 4;
|
||||
const res = new Map();
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
const resk = this.key_handler.deserialize(view, offset);
|
||||
const resv = this.value_handler.deserialize(view, resk.offset);
|
||||
offset = resv.offset;
|
||||
res.set(resk.value, resv.value);
|
||||
}
|
||||
return new DeserializedResult(res, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles storage and serialization of UUID objects using a 16-byte buffer.
|
||||
* @extends {BaseTypeHandler}
|
||||
@ -848,7 +974,7 @@ export class CompoundTypeHandler extends BaseTypeHandler {
|
||||
let res = 0;
|
||||
for (let i = 0; i < this.typedef.length; i += 1) {
|
||||
const field_name = this.typedef[i].field;
|
||||
const field_handler = this.typedef[i].type;
|
||||
const field_handler = getHandlerObject(this.typedef[i].type);
|
||||
res += field_handler.sizeof(value[field_name]);
|
||||
}
|
||||
return res;
|
||||
@ -864,7 +990,7 @@ export class CompoundTypeHandler extends BaseTypeHandler {
|
||||
serialize(view, offset, value) {
|
||||
for (let i = 0; i < this.typedef.length; i += 1) {
|
||||
const field_name = this.typedef[i].field;
|
||||
const field_handler = this.typedef[i].type;
|
||||
const field_handler = getHandlerObject(this.typedef[i].type);
|
||||
offset = field_handler.serialize(view, offset, value[field_name]);
|
||||
}
|
||||
return offset;
|
||||
@ -880,7 +1006,7 @@ export class CompoundTypeHandler extends BaseTypeHandler {
|
||||
let res = new this.type();
|
||||
for (let i = 0; i < this.typedef.length; i += 1) {
|
||||
const field_name = this.typedef[i].field;
|
||||
const field_handler = this.typedef[i].type;
|
||||
const field_handler = getHandlerObject(this.typedef[i].type);
|
||||
const tmp = field_handler.deserialize(view, offset);
|
||||
res[field_name] = tmp.value;
|
||||
offset = tmp.offset;
|
||||
@ -908,4 +1034,10 @@ export const BASIC_TYPES = {
|
||||
uuid: new UUIDHandler(),
|
||||
str: new StringHandler(),
|
||||
DateTime: new DateHandler(),
|
||||
|
||||
array: (type) => new DynamicArrayHandler(type),
|
||||
FixedArray: (n, type) => new FixedArrayHandler(n, type),
|
||||
raw: (n) => new RawBufferHandler(n),
|
||||
map: (k, v) => new MapHandler(k, v),
|
||||
StringMap: new MapHandler(new StringHandler(), new StringHandler()),
|
||||
};
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { Queue } from './queue.mjs';
|
||||
|
||||
import { Queue } from './queue.mjs';
|
||||
|
||||
/**
|
||||
* Represents an asynchronous lock for managing access to a shared resource.
|
||||
* @class
|
||||
|
Loading…
x
Reference in New Issue
Block a user