[js]add tests for bstruct

This commit is contained in:
方而静 2024-02-10 19:49:08 +08:00
parent 023e8e34f9
commit 1378dbf10a
Signed by: szTom
GPG Key ID: 072D999D60C6473C
9 changed files with 474 additions and 66 deletions

View File

@ -1 +1,35 @@
import { VirtualMethodNotImplementedError } from '@og/error-utils';
import { BaseTypeHandler, CompoundTypeHandler } from './type-handler.mjs';
export { BASIC_TYPES, FixedArrayHandler, DynamicArrayHandler, CompoundTypeHandler } from './type-handler.mjs';
/**
* Serializes JavaScript value to binary.
* @param {any} value - value to serialize.
* @param {BaseTypeHandler} type - type handler of the value.
* @returns {ArrayBuffer} - the serialized binary buffer.
*/
export function serializeToBinary(value, type) {
if (!(type instanceof BaseTypeHandler)) {
type = new CompoundTypeHandler(type);
}
const res = new ArrayBuffer(type.sizeof(value));
const view = new DataView(res);
type.serialize(view, 0, value);
return res;
}
/**
* Deserializes binary back to JavaScript value.
* @param {DataView} view - buffer to deserialize.
* @param {BaseTypeHandler} type - type handler of the desired value.
* @returns {any} - the deserialized JavaScript value.
*/
export function deserializeFromBinary(view, type) {
if (!(type instanceof BaseTypeHandler)) {
type = new CompoundTypeHandler(type);
}
const tmp = type.deserialize(view, 0);
return tmp.value;
}

View File

@ -4,6 +4,7 @@
"main": "index.mjs",
"dependencies": {
"@og/error-utils": "file:../error-utils",
"@og/uuid": "file:../uuid"
"@og/uuid": "file:../uuid",
"@og/utility": "file:../utility"
}
}

View File

@ -0,0 +1,197 @@
import { BASIC_TYPES, FixedArrayHandler, DynamicArrayHandler, CompoundTypeHandler, serializeToBinary, deserializeFromBinary } from '../index.mjs';
import assert from 'node:assert/strict';
import { areArrayBuffersEqual } from '@og/utility';
import { UUID } from '@og/uuid';
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
foo() {
return this.x + this.y;
}
}
Point.typedef = [
{ field: 'x', type: BASIC_TYPES.u8 },
{ field: 'y', type: BASIC_TYPES.u8 },
];
describe('binary-struct', () => {
describe('serializeToBinary', () => {
it('type i8', () => {
let res = serializeToBinary(-123, BASIC_TYPES.i8); // Example value for i8
let ans = new Uint8Array([0x85]); // Byte representation of -123 as i8
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type i16', () => {
let res = serializeToBinary(-12345, BASIC_TYPES.i16); // Example value for i16
let ans = new Uint8Array([0xc7, 0xcf]); // Byte representation of -12345 as i16
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type i32', () => {
let res = serializeToBinary(-1234567890, BASIC_TYPES.i32); // Example value for i32
let ans = new Uint8Array([0x2e, 0xfd, 0x69, 0xb6]); // Byte representation of -1234567890 as i32
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type i64', () => {
let res = serializeToBinary(-1234567890123456789n, BASIC_TYPES.i64); // Example value for i64
let ans = new Uint8Array([0xeb, 0x7e, 0x16, 0x82, 0x0b, 0xef, 0xdd, 0xee]); // Byte representation of -1234567890123456789 as i64
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type u8', () => {
let res = serializeToBinary(60, BASIC_TYPES.u8); // Example value for u8
let ans = new Uint8Array([0x3c]); // Byte representation of 60 as u8
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type u16', () => {
let res = serializeToBinary(56789, BASIC_TYPES.u16); // Example value for u16
let ans = new Uint8Array([0xd5, 0xdd]); // Byte representation of 56789 as u16
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type u32', () => {
let res = serializeToBinary(1234567890, BASIC_TYPES.u32); // Example value for u32
let ans = new Uint8Array([0xd2, 0x02, 0x96, 0x49]); // Byte representation of 1234567890 as u32
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type u64', () => {
let res = serializeToBinary(123456789009876543n, BASIC_TYPES.u64); // Example value for u64
let ans = new Uint8Array([0x3f, 0x46, 0x0b, 0xa6, 0x4b, 0x9b, 0xb6, 0x01]); // Byte representation of 123456789009876543 as u64
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type uuid', () => {
let res = serializeToBinary(new UUID('f5b3ad32-2a77-4f2e-a3b8-3eb8a8546f2b'), BASIC_TYPES.uuid);
let ans = new Uint8Array([0xf5, 0xb3, 0xad, 0x32, 0x2a, 0x77, 0x4f, 0x2e, 0xa3, 0xb8, 0x3e, 0xb8, 0xa8, 0x54, 0x6f, 0x2b]);
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type string', () => {
let res = serializeToBinary('hello world', BASIC_TYPES.str);
let ans = new Uint8Array([0x0b, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]);
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type u16[]', () => {
let res = serializeToBinary([0x1770, 0x3c3a, 0x9012], new DynamicArrayHandler(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 ans = new Uint8Array([0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]);
assert.ok(areArrayBuffersEqual(res, ans));
});
it('type Point', () => {
let res = serializeToBinary(new Point(2, 3), Point);
let ans = new Uint8Array([0x02, 0x03]);
assert.ok(areArrayBuffersEqual(res, ans));
});
});
describe('deserializeFromBinary', () => {
it('type i8', () => {
let binaryData = new Uint8Array([0x85]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.i8);
let ans = -123;
assert.equal(res, ans);
});
it('type i16', () => {
let binaryData = new Uint8Array([0xc7, 0xcf]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.i16);
let ans = -12345;
assert.equal(res, ans);
});
it('type i32', () => {
let binaryData = new Uint8Array([0x2e, 0xfd, 0x69, 0xb6]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.i32);
let ans = -1234567890;
assert.equal(res, ans);
});
it('type i64', () => {
let binaryData = new Uint8Array([0xeb, 0x7e, 0x16, 0x82, 0x0b, 0xef, 0xdd, 0xee]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.i64);
let ans = BigInt('-1234567890123456789');
assert.equal(res, ans);
});
it('type u8', () => {
let binaryData = new Uint8Array([0x3c]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.u8);
let ans = 60;
assert.equal(res, ans);
});
it('type u16', () => {
let binaryData = new Uint8Array([0xd5, 0xdd]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.u16);
let ans = 56789;
assert.equal(res, ans);
});
it('type u32', () => {
let binaryData = new Uint8Array([0xd2, 0x02, 0x96, 0x49]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.u32);
let ans = 1234567890;
assert.equal(res, ans);
});
it('type u64', () => {
let binaryData = new Uint8Array([0x3f, 0x46, 0x0b, 0xa6, 0x4b, 0x9b, 0xb6, 0x01]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.u64);
let ans = BigInt('123456789009876543');
assert.equal(res, ans);
});
it('type uuid', () => {
let binaryData = new Uint8Array([0xf5, 0xb3, 0xad, 0x32, 0x2a, 0x77, 0x4f, 0x2e, 0xa3, 0xb8, 0x3e, 0xb8, 0xa8, 0x54, 0x6f, 0x2b]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.uuid);
let ans = 'f5b3ad32-2a77-4f2e-a3b8-3eb8a8546f2b';
assert.equal(res.toString(), ans);
});
it('type string', () => {
let binaryData = new Uint8Array([0x0b, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), BASIC_TYPES.str);
let ans = 'hello world';
assert.equal(res, ans);
});
it('type u16[]', () => {
let binaryData = new Uint8Array([0x03, 0x00, 0x00, 0x00, 0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), new DynamicArrayHandler(BASIC_TYPES.u16));
let ans = [0x1770, 0x3c3a, 0x9012];
assert.deepEqual(res, ans);
});
it('type u16[3]', () => {
let binaryData = new Uint8Array([0x70, 0x17, 0x3a, 0x3c, 0x12, 0x90]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), new FixedArrayHandler(3, BASIC_TYPES.u16));
let ans = [0x1770, 0x3c3a, 0x9012];
assert.deepEqual(res, ans);
});
it('type Point', () => {
let binaryData = new Uint8Array([0x02, 0x03]).buffer;
let res = deserializeFromBinary(new DataView(binaryData), Point);
let ans = new Point(2, 3);
assert.equal(res.x, ans.x);
assert.equal(res.y, ans.y);
assert.equal(res.foo(), ans.foo())
});
});
});

View File

@ -22,7 +22,7 @@ export class DeserializedResult {
* @abstract
* @class
*/
export class BasicTypeHandler {
export class BaseTypeHandler {
/**
* Gets the size of the serialized value in bytes.
* @abstract
@ -59,10 +59,10 @@ export class BasicTypeHandler {
/**
* Handles 8-bit signed integers (int8).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Int8Handler extends BasicTypeHandler {
export class Int8Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized int8 value in bytes (always 1).
* @param {number} _value - The int8 value.
@ -97,10 +97,10 @@ export class Int8Handler extends BasicTypeHandler {
/**
* Handles 16-bit signed integers (int16).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Int16Handler extends BasicTypeHandler {
export class Int16Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized int16 value in bytes (always 2).
* @param {number} _value - The int16 value.
@ -118,7 +118,7 @@ export class Int16Handler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setInt16(offset, value);
view.setInt16(offset, value, true);
return offset + 2;
}
@ -129,16 +129,16 @@ export class Int16Handler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the int16 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getInt16(offset), offset + 2);
return new DeserializedResult(view.getInt16(offset, true), offset + 2);
}
}
/**
* Handles 32-bit signed integers (int32).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Int32Handler extends BasicTypeHandler {
export class Int32Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized int32 value in bytes (always 4).
* @param {number} _value - The int32 value.
@ -156,7 +156,7 @@ export class Int32Handler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setInt32(offset, value);
view.setInt32(offset, value, true);
return offset + 4;
}
@ -167,16 +167,16 @@ export class Int32Handler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the int32 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getInt32(offset), offset + 4);
return new DeserializedResult(view.getInt32(offset, true), offset + 4);
}
}
/**
* Handles 64-bit signed integers (int64).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Int64Handler extends BasicTypeHandler {
export class Int64Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized int64 value in bytes (always 8).
* @param {BigInt} _value - The int64 value.
@ -194,7 +194,7 @@ export class Int64Handler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setBigInt64(offset, value);
view.setBigInt64(offset, value, true);
return offset + 8;
}
@ -205,16 +205,16 @@ export class Int64Handler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the int64 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getBigInt64(offset), offset + 8);
return new DeserializedResult(view.getBigInt64(offset, true), offset + 8);
}
}
/**
* Handles 8-bit unsigned integers (uint8).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Uint8Handler extends BasicTypeHandler {
export class Uint8Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized uint8 value in bytes (always 1).
* @param {number} _value - The uint8 value.
@ -249,10 +249,10 @@ export class Uint8Handler extends BasicTypeHandler {
/**
* Handles 16-bit unsigned integers (uint16).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Uint16Handler extends BasicTypeHandler {
export class Uint16Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized uint16 value in bytes (always 2).
* @param {number} _value - The uint16 value.
@ -270,7 +270,7 @@ export class Uint16Handler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setUint16(offset, value);
view.setUint16(offset, value, true);
return offset + 2;
}
@ -281,16 +281,16 @@ export class Uint16Handler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the uint16 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getUint16(offset), offset + 2);
return new DeserializedResult(view.getUint16(offset, true), offset + 2);
}
}
/**
* Handles 32-bit unsigned integers (uint32).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Uint32Handler extends BasicTypeHandler {
export class Uint32Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized uint32 value in bytes (always 4).
* @param {number} _value - The uint32 value.
@ -308,7 +308,7 @@ export class Uint32Handler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setUint32(offset, value);
view.setUint32(offset, value, true);
return offset + 4;
}
@ -319,16 +319,16 @@ export class Uint32Handler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the uint32 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getUint32(offset), offset + 4);
return new DeserializedResult(view.getUint32(offset, true), offset + 4);
}
}
/**
* Handles 64-bit unsigned integers (uint64).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class Uint64Handler extends BasicTypeHandler {
export class Uint64Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized uint64 value in bytes (always 8).
* @param {BigInt} _value - The uint64 value.
@ -346,7 +346,7 @@ export class Uint64Handler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setBigUint64(offset, value);
view.setBigUint64(offset, value, true);
return offset + 8;
}
@ -357,16 +357,92 @@ export class Uint64Handler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the uint64 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getBigUint64(offset), offset + 8);
return new DeserializedResult(view.getBigUint64(offset, true), offset + 8);
}
}
/**
* Handles 32-bit floating point numbers (float32).
* @extends {BaseTypeHandler}
* @class
*/
export class Float32Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized float32 value in bytes (always 4).
* @param {number} _value - The float32 value.
* @returns {number} - The size of the serialized float32 value in bytes.
*/
sizeof(_value) {
return 4;
}
/**
* Serializes the float32 value 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 {number} value - The float32 value to be serialized.
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setFloat32(offset, value);
return offset + 4;
}
/**
* Deserializes the float32 value 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 float32 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getFloat32(offset), offset + 4);
}
}
/**
* Handles 64-bit floating point numbers (float64).
* @extends {BaseTypeHandler}
* @class
*/
export class Float64Handler extends BaseTypeHandler {
/**
* Gets the size of the serialized float64 value in bytes (always 8).
* @param {number} _value - The float64 value.
* @returns {number} - The size of the serialized float64 value in bytes.
*/
sizeof(_value) {
return 8;
}
/**
* Serializes the float64 value 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 {number} value - The float64 value to be serialized.
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setFloat64(offset, value);
return offset + 8;
}
/**
* Deserializes the float64 value 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 float64 value and a new offset.
*/
deserialize(view, offset) {
return new DeserializedResult(view.getFloat64(offset), offset + 8);
}
}
/**
* Handles boolean values (bool).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class BoolHandler extends BasicTypeHandler {
export class BoolHandler extends BaseTypeHandler {
/**
* Gets the size of the serialized bool value in bytes (always 1).
* @param {boolean} _value - The bool value.
@ -401,10 +477,10 @@ export class BoolHandler extends BasicTypeHandler {
/**
* Handles void values (void).
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class VoidHandler extends BasicTypeHandler {
export class VoidHandler extends BaseTypeHandler {
/**
* Gets the size of the serialized void value in bytes (always 0).
* @param {*} _value - The void value.
@ -438,14 +514,14 @@ export class VoidHandler extends BasicTypeHandler {
/**
* Handles array of a fixed length with elements of the same type.
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class FixedArrayHandler extends BasicTypeHandler {
export class FixedArrayHandler extends BaseTypeHandler {
/**
* Constructor for FixedArrayHandler.
* @param {number} n - The fixed length of the array.
* @param {BasicTypeHandler} element_handler - The handler for individual elements of the array.
* @param {BaseTypeHandler} element_handler - The handler for individual elements of the array.
*/
constructor(n, element_handler) {
super();
@ -499,13 +575,13 @@ export class FixedArrayHandler extends BasicTypeHandler {
/**
* Handles dynamic arrays with elements of the same type.
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class DynamicArrayHandler extends BasicTypeHandler {
export class DynamicArrayHandler extends BaseTypeHandler {
/**
* Constructor for DynamicArrayHandler.
* @param {BasicTypeHandler} element_handler - The handler for individual elements of the array.
* @param {BaseTypeHandler} element_handler - The handler for individual elements of the array.
*/
constructor(element_handler) {
super();
@ -533,7 +609,7 @@ export class DynamicArrayHandler extends BasicTypeHandler {
* @returns {number} - The new offset after serialization.
*/
serialize(view, offset, value) {
view.setUint32(offset, value.length);
view.setUint32(offset, value.length, true);
offset += 4;
for (const element of value) {
offset = this.element_handler.serialize(view, offset, element);
@ -548,7 +624,7 @@ export class DynamicArrayHandler extends BasicTypeHandler {
* @returns {DeserializedResult} - The deserialized result containing the dynamic array and a new offset.
*/
deserialize(view, offset) {
const length = view.getUint32(offset);
const length = view.getUint32(offset, true);
offset += 4;
const res = new Array(length);
for (let i = 0; i < length; i++) {
@ -562,10 +638,19 @@ export class DynamicArrayHandler extends BasicTypeHandler {
/**
* Handles storage and serialization of UUID objects using a 16-byte buffer.
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class UUIDHandler extends BasicTypeHandler {
export class UUIDHandler extends BaseTypeHandler {
/**
* Gets the size of the serialized UUID value in bytes (always 16).
* @param {boolean} _value - The UUID value.
* @returns {number} - The size of the serialized UUID value in bytes.
*/
sizeof(_value) {
return 16;
}
/**
* Serializes the UUID object and writes it to the buffer at the specified offset.
* @param {DataView} view - The DataView to write to.
@ -606,17 +691,10 @@ export class UUIDHandler extends BasicTypeHandler {
/**
* Handles storage and serialization of strings.
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class StringHandler extends BasicTypeHandler {
/**
* Constructs a StringHandler object.
*/
constructor() {
super();
}
export class StringHandler extends BaseTypeHandler {
/**
* Gets the size of the serialized string in bytes.
* @param {string} value - The string to calculate the size for.
@ -644,7 +722,7 @@ export class StringHandler extends BasicTypeHandler {
const encoded_string = encoder.encode(value);
// Write the length of the string as a uint32 at the specified offset
view.setUint32(offset, encoded_string.length);
view.setUint32(offset, encoded_string.length, true);
offset += 4;
// Write the UTF-8 encoded string to the DataView starting at offset + 4 (after the length)
@ -664,7 +742,7 @@ export class StringHandler extends BasicTypeHandler {
*/
deserialize(view, offset) {
// Read the length of the string as a uint32 at the specified offset
const length = view.getUint32(offset);
const length = view.getUint32(offset, true);
offset += 4;
// Read the UTF-8 encoded string from the DataView starting at offset + 4 (after the length)
@ -681,10 +759,10 @@ export class StringHandler extends BasicTypeHandler {
/**
* Handles the serialization and deserialization of a compound type composed of various fields.
* @extends {BasicTypeHandler}
* @extends {BaseTypeHandler}
* @class
*/
export class CompoundTypeHandler extends BasicTypeHandler {
export class CompoundTypeHandler extends BaseTypeHandler {
/**
* Constructs a CompoundTypeHandler object for the specified type.
* @param {Function} type - The class representing the compound type.
@ -698,9 +776,9 @@ export class CompoundTypeHandler extends BasicTypeHandler {
* }
*
* // Define the type definition for Point
* Point.prototype.typedef = [
* {field: 'x', handler: new Float32Handler()},
* {field: 'y', handler: new Float32Handler()}
* Point.typedef = [
* {field: 'x', type: BASIC_TYPES.f32},
* {field: 'y', type: BASIC_TYPES.f32}
* ];
*
* // Create a CompoundTypeHandler for Point
@ -716,7 +794,7 @@ export class CompoundTypeHandler extends BasicTypeHandler {
this.type = type;
/**
* The type definition specifying the fields and their handlers.
* @type {Array<{field: string, handler: BasicTypeHandler}>}
* @type {Array<{field: string, type: BaseTypeHandler}>}
* @private
*/
this.typedef = type.typedef;
@ -731,7 +809,7 @@ export class CompoundTypeHandler extends BasicTypeHandler {
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].handler;
const field_handler = this.typedef[i].type;
res += field_handler.sizeof(value[field_name]);
}
return res;
@ -747,7 +825,7 @@ export class CompoundTypeHandler extends BasicTypeHandler {
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].handler;
const field_handler = this.typedef[i].type;
offset = field_handler.serialize(view, offset, value[field_name]);
}
return offset;
@ -763,7 +841,7 @@ export class CompoundTypeHandler extends BasicTypeHandler {
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].handler;
const field_handler = this.typedef[i].type;
const tmp = field_handler.deserialize(view, offset);
res[field_name] = tmp.value;
offset = tmp.offset;
@ -771,3 +849,23 @@ export class CompoundTypeHandler extends BasicTypeHandler {
return new DeserializedResult(res, offset);
}
}
export const BASIC_TYPES = {
i8: new Int8Handler(),
i16: new Int16Handler(),
i32: new Int32Handler(),
i64: new Int64Handler(),
u8: new Uint8Handler(),
u16: new Uint16Handler(),
u32: new Uint32Handler(),
u64: new Uint64Handler(),
f32: new Float64Handler(),
f64: new Float64Handler(),
bool: new BoolHandler(),
void: new VoidHandler(),
uuid: new UUIDHandler(),
str: new StringHandler(),
};

23
shared/utility/buffer.mjs Normal file
View File

@ -0,0 +1,23 @@
/**
* Compares two ArrayBuffer objects byte by byte to check for equality.
*
* @param {ArrayBufferLike | Int32Array | Uint32Array | Int16Array | Uint16Array | Int8Array | Uint8Array | Uint8ClampedArray} buffer1 - The first ArrayBuffer to compare.
* @param {ArrayBufferLike | Int32Array | Uint32Array | Int16Array | Uint16Array | Int8Array | Uint8Array | Uint8ClampedArray} buffer2 - The second ArrayBuffer to compare.
* @returns {boolean} Returns true if the ArrayBuffer objects are equal byte by byte, otherwise false.
*/
export function areArrayBuffersEqual(buffer1, buffer2) {
if (buffer1.byteLength !== buffer2.byteLength) {
return false;
}
const view1 = new DataView(buffer1.buffer ?? buffer1);
const view2 = new DataView(buffer2.buffer ?? buffer2);
for (let i = 0; i < buffer1.byteLength; i++) {
if (view1.getUint8(i) !== view2.getUint8(i)) {
return false;
}
}
return true;
}

1
shared/utility/index.mjs Normal file
View File

@ -0,0 +1 @@
export { areArrayBuffersEqual } from './buffer.mjs';

View File

@ -0,0 +1,6 @@
{
"name": "@og/utility",
"type": "module",
"main": "index.mjs",
"dependencies": {}
}

View File

@ -0,0 +1,48 @@
// test.js
import assert from 'node:assert/strict';
import { areArrayBuffersEqual } from '../buffer.mjs';
describe('areArrayBuffersEqual', function () {
it('should return true for equal ArrayBuffers', function () {
const buffer1 = new ArrayBuffer(4);
const view1 = new DataView(buffer1);
view1.setInt8(0, 1);
view1.setInt8(1, 2);
view1.setInt8(2, 3);
view1.setInt8(3, 4);
const buffer2 = new ArrayBuffer(4);
const view2 = new DataView(buffer2);
view2.setInt8(0, 1);
view2.setInt8(1, 2);
view2.setInt8(2, 3);
view2.setInt8(3, 4);
assert.equal(areArrayBuffersEqual(buffer1, buffer2), true);
});
it('should return false for different length ArrayBuffers', function () {
const buffer1 = new ArrayBuffer(4);
const buffer2 = new ArrayBuffer(8);
assert.equal(areArrayBuffersEqual(buffer1, buffer2), false);
});
it('should return false for different content ArrayBuffers', function () {
const buffer1 = new ArrayBuffer(4);
const view1 = new DataView(buffer1);
view1.setInt8(0, 1);
view1.setInt8(1, 2);
view1.setInt8(2, 3);
view1.setInt8(3, 4);
const buffer2 = new ArrayBuffer(4);
const view2 = new DataView(buffer2);
view2.setInt8(0, 5);
view2.setInt8(1, 6);
view2.setInt8(2, 7);
view2.setInt8(3, 8);
assert.equal(areArrayBuffersEqual(buffer1, buffer2), false);
});
});

View File

@ -1,5 +1,5 @@
import { UUID } from '../index.mjs';
import assert from 'node:assert';
import assert from 'node:assert/strict';
describe('UUID', () => {
describe('#constructor()', () => {