import { VirtualMethodNotImplementedError } from '@og/error-utils'; export class BasicTypeHandler { sizeof(value) { throw new VirtualMethodNotImplementedError(); } serialize(view, offset, value) { throw new VirtualMethodNotImplementedError(); } deserialize(view, offset) { throw new VirtualMethodNotImplementedError(); } }; export class Int8Handler extends BasicTypeHandler { sizeof(_value) { return 1; } /** * * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setInt8(offset, value); } /** * * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getInt8(offset); } } export class Int16Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 2; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setInt16(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getInt16(offset); } } export class Int32Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 4; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setInt32(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getInt32(offset); } } export class Int64Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 8; } /** * @param {DataView} view * @param {number} offset * @param {BigInt} value */ serialize(view, offset, value) { view.setBigInt64(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {BigInt} */ deserialize(view, offset) { return view.getBigInt64(offset); } } export class Uint8Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 1; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setUint8(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getUint8(offset); } } export class Uint16Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 2; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setUint16(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getUint16(offset); } } export class Uint32Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 4; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setUint32(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getUint32(offset); } } export class Uint64Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 8; } /** * @param {DataView} view * @param {number} offset * @param {BigInt} value */ serialize(view, offset, value) { view.setBigUint64(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {BigInt} */ deserialize(view, offset) { return view.getBigUint64(offset); } } export class Float32Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 4; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setFloat32(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getFloat32(offset); } } export class Float64Handler extends BasicTypeHandler { /** * @param {number} _value * @returns {number} */ sizeof(_value) { return 8; } /** * @param {DataView} view * @param {number} offset * @param {number} value */ serialize(view, offset, value) { view.setFloat64(offset, value); } /** * @param {DataView} view * @param {number} offset * @returns {number} */ deserialize(view, offset) { return view.getFloat64(offset); } } export class BoolHandler extends BasicTypeHandler { /** * @param {boolean} _value * @returns {number} */ sizeof(_value) { return 1; } /** * @param {DataView} view * @param {number} offset * @param {boolean} value */ serialize(view, offset, value) { view.setUint8(offset, value ? 1 : 0); } /** * @param {DataView} view * @param {number} offset * @returns {boolean} */ deserialize(view, offset) { return view.getUint8(offset) !== 0; } } export class VoidHandler extends BasicTypeHandler { /** * @returns {number} */ sizeof() { return 0; } /** * @param {DataView} _view * @param {number} _offset * @param {undefined} _value */ serialize(_view, _offset, _value) { // Do nothing for Void } /** * @param {DataView} _view * @param {number} _offset * @returns {undefined} */ deserialize(_view, _offset) { // Do nothing for Void } } export class UUIDHandler extends BasicTypeHandler { /** * @param {UUID} _value * @returns {number} */ sizeof(_value) { return 16; } /** * @param {DataView} view * @param {number} offset * @param {UUID} value */ serialize(view, offset, value) { const buffer = value.buffer; for (let i = 0; i < buffer.length; i++) { view.setUint8(offset + i, buffer[i]); } } /** * @param {DataView} view * @param {number} offset * @returns {UUID} */ deserialize(view, offset) { const buffer = new Uint8Array(16); for (let i = 0; i < 16; i++) { buffer[i] = view.getUint8(offset + i); } return new UUID(buffer); } } export class StringHandler extends BasicTypeHandler { /** * @param {string} _value * @returns {number} */ sizeof(_value) { // Calculate the size of string in bytes including the 4 bytes for length return 4 + this.utf8ByteLength(_value); } /** * @param {DataView} view * @param {number} offset * @param {string} value */ serialize(view, offset, value) { const utf8_bytes = this.encodeUTF8(value); // Write string length as 4-byte unsigned integer view.setUint32(offset, utf8_bytes.length, true); // Write UTF-8 bytes for (let i = 0; i < utf8_bytes.length; i++) { view.setUint8(offset + 4 + i, utf8_bytes[i]); } } /** * @param {DataView} view * @param {number} offset * @returns {string} */ deserialize(view, offset) { // Read string length as 4-byte unsigned integer const length = view.getUint32(offset, true); // Read UTF-8 bytes const utf8_bytes = new Uint8Array(length); for (let i = 0; i < length; i++) { utf8_bytes[i] = view.getUint8(offset + 4 + i); } // Decode UTF-8 bytes to string return this.decodeUTF8(utf8_bytes); } /** * Encodes a string to UTF-8 bytes. * @param {string} str * @returns {Uint8Array} */ encodeUTF8(str) { const encoder = new TextEncoder(); return encoder.encode(str); } /** * Decodes UTF-8 bytes to a string. * @param {Uint8Array} bytes * @returns {string} */ decodeUTF8(bytes) { const decoder = new TextDecoder(); return decoder.decode(bytes); } /** * Calculates the byte length of a string encoded in UTF-8. * @param {string} str * @returns {number} */ utf8ByteLength(str) { return new TextEncoder().encode(str).length; } }