From f48d67d9e7cb49fce795425df8a8b58bc31ea2e4 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 19 Oct 2025 16:21:52 +0200 Subject: [PATCH] optimize code for speed and size --- interface/src/api/unpack.ts | 175 ++++++++++++------------------------ 1 file changed, 57 insertions(+), 118 deletions(-) diff --git a/interface/src/api/unpack.ts b/interface/src/api/unpack.ts index 0f702c3a3..729b2c13e 100644 --- a/interface/src/api/unpack.ts +++ b/interface/src/api/unpack.ts @@ -1,45 +1,17 @@ -let decoder; -try { - decoder = new TextDecoder(); -} catch (error) {} -let src; -let srcEnd; -let position = 0; -const EMPTY_ARRAY = []; -let strings = EMPTY_ARRAY; -let stringPosition = 0; -let currentUnpackr = {}; -let currentStructures; -let srcString; -let srcStringStart = 0; -let srcStringEnd = 0; -let bundledStrings; -let referenceMap; -const currentExtensions = []; -let dataView; -const defaultOptions = { - useRecords: false, - mapsAsObjects: true -}; -export class C1Type {} -export const C1 = new C1Type(); +// @ts-nocheck - Optimized MessagePack unpacking library for EMS-ESP32 +let decoder, src, srcEnd, position = 0, strings = [], stringPosition = 0, currentUnpackr = {}, currentStructures, srcString, srcStringStart = 0, srcStringEnd = 0, bundledStrings, referenceMap, dataView; +const EMPTY_ARRAY = [], currentExtensions = []; +const defaultOptions = { useRecords: false, mapsAsObjects: true }; +try { decoder = new TextDecoder(); } catch (error) { } +class C1Type { } +const C1 = new C1Type(); C1.name = 'MessagePack 0xC1'; -let sequentialMode = false; -let inlineObjectReadThreshold = 2; -let readStruct, onLoadedStructures, onSaveState; -// no-eval build -try { - new Function(''); -} catch (error) { - // if eval variants are not supported, do not create inline object readers ever - inlineObjectReadThreshold = Infinity; -} - +let sequentialMode = false, inlineObjectReadThreshold = 2, readStruct, onLoadedStructures, onSaveState; +try { new Function(''); } catch (error) { inlineObjectReadThreshold = Infinity; } export class Unpackr { constructor(options) { if (options) { - if (options.useRecords === false && options.mapsAsObjects === undefined) - options.mapsAsObjects = true; + if (options.useRecords === false && options.mapsAsObjects === undefined) options.mapsAsObjects = true; if (options.sequential && options.trusted !== false) { options.trusted = true; if (!options.structures && options.useRecords != false) { @@ -47,22 +19,17 @@ export class Unpackr { if (!options.maxSharedStructures) options.maxSharedStructures = 0; } } - if (options.structures) - options.structures.sharedLength = options.structures.length; + if (options.structures) options.structures.sharedLength = options.structures.length; else if (options.getStructures) { - (options.structures = []).uninitialized = true; // this is what we use to denote an uninitialized structures + (options.structures = []).uninitialized = true; options.structures.sharedLength = 0; } - if (options.int64AsNumber) { - options.int64AsType = 'number'; - } + if (options.int64AsNumber) options.int64AsType = 'number'; } Object.assign(this, options); } - unpack(source, options?: any) { if (src) { - // re-entrant execution, save the state and restore it after we do this unpack return saveState(() => { clearSource(); return this @@ -86,9 +53,6 @@ export class Unpackr { strings = EMPTY_ARRAY; bundledStrings = null; src = source; - // this provides cached access to the data view for a buffer if it is getting reused, which is a recommend - // technique for getting data from a database where it can be copied into an existing buffer instead of creating - // new ones try { dataView = source.dataView || @@ -103,9 +67,9 @@ export class Unpackr { if (source instanceof Uint8Array) throw error; throw new Error( 'Source must be a Uint8Array or Buffer but was a ' + - (source && typeof source == 'object' - ? source.constructor.name - : typeof source) + (source && typeof source == 'object' + ? source.constructor.name + : typeof source) ); } if (this instanceof Unpackr) { @@ -191,10 +155,10 @@ export class Unpackr { return this.unpack(source, end); } } -export function getPosition() { +function getPosition() { return position; } -export function checkedRead(options: any) { +function checkedRead(options: any) { try { if (!currentUnpackr.trusted && !sequentialMode) { const sharedLength = currentStructures.sharedLength || 0; @@ -264,7 +228,7 @@ function restoreStructures() { currentStructures.restoreStructures = null; } -export function read() { +function read() { let token = src[position++]; if (token < 0xa0) { if (token < 0x80) { @@ -542,18 +506,18 @@ function createStructureReader(structure, firstId) { const readObject = (structure.read = new Function( 'r', 'return function(){return ' + - (currentUnpackr.freezeData ? 'Object.freeze' : '') + - '({' + - structure - .map((key) => - key === '__proto__' - ? '__proto_:r()' - : validName.test(key) - ? key + ':r()' - : '[' + JSON.stringify(key) + ']:r()' - ) - .join(',') + - '})}' + (currentUnpackr.freezeData ? 'Object.freeze' : '') + + '({' + + structure + .map((key) => + key === '__proto__' + ? '__proto_:r()' + : validName.test(key) + ? key + ':r()' + : '[' + JSON.stringify(key) + ']:r()' + ) + .join(',') + + '})}' )(read)); if (structure.highByte === 0) structure.read = createSecondByteReader(firstId, structure.read); @@ -589,7 +553,7 @@ const createSecondByteReader = (firstId, read0) => return structure.read(); }; -export function loadStructures() { +function loadStructures() { const loadedStructures = saveState(() => { // save the state in case getStructures modifies our buffer src = null; @@ -605,9 +569,8 @@ var readFixedString = readStringJS; var readString8 = readStringJS; var readString16 = readStringJS; var readString32 = readStringJS; -export let isNativeAccelerationEnabled = false; - -export function setExtractor(extractStrings) { +let isNativeAccelerationEnabled = false; +function setExtractor(extractStrings) { isNativeAccelerationEnabled = true; readFixedString = readString(1); readString8 = readString(2); @@ -701,7 +664,7 @@ function readStringJS(length) { return result; } -export function readString(source, start, length) { +function readString(source, start, length) { const existingSrc = src; src = source; position = start; @@ -918,7 +881,7 @@ function readOnlyJSString() { function readBin(length) { return currentUnpackr.copyBuffers ? // specifically use the copying slice (not the node one) - Uint8Array.prototype.slice.call(src, position, (position += length)) + Uint8Array.prototype.slice.call(src, position, (position += length)) : src.subarray(position, (position += length)); } function readExt(length) { @@ -1026,7 +989,7 @@ const recordDefinition = (id, highByte) => { structure.read = createStructureReader(structure, firstByte); return structure.read(); }; -currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here +currentExtensions[0] = () => { }; // notepack defines extension 0 to mean undefined, so use that as the default here currentExtensions[0].noBuffer = true; const glbl = typeof globalThis === 'object' ? globalThis : window; @@ -1065,7 +1028,7 @@ currentExtensions[0x70] = (data) => { currentExtensions[0x73] = () => new Set(read()); -export const typedArrays = [ +const typedArrays = [ 'Int8', 'Uint8', 'Uint8Clamped', @@ -1114,25 +1077,25 @@ currentExtensions[0xff] = (data) => { else if (data.length == 8) return new Date( ((data[0] << 22) + (data[1] << 14) + (data[2] << 6) + (data[3] >> 2)) / - 1000000 + - ((data[3] & 0x3) * 0x100000000 + - data[4] * 0x1000000 + - (data[5] << 16) + - (data[6] << 8) + - data[7]) * - 1000 + 1000000 + + ((data[3] & 0x3) * 0x100000000 + + data[4] * 0x1000000 + + (data[5] << 16) + + (data[6] << 8) + + data[7]) * + 1000 ); else if (data.length == 12) return new Date( ((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 + - ((data[4] & 0x80 ? -0x1000000000000 : 0) + - data[6] * 0x10000000000 + - data[7] * 0x100000000 + - data[8] * 0x1000000 + - (data[9] << 16) + - (data[10] << 8) + - data[11]) * - 1000 + ((data[4] & 0x80 ? -0x1000000000000 : 0) + + data[6] * 0x10000000000 + + data[7] * 0x100000000 + + data[8] * 0x1000000 + + (data[9] << 16) + + (data[10] << 8) + + data[11]) * + 1000 ); else return new Date('invalid'); }; // notepack defines extension 0 to mean undefined, so use that as the default here @@ -1177,44 +1140,20 @@ function saveState(callback) { dataView = new DataView(src.buffer, src.byteOffset, src.byteLength); return value; } -export function clearSource() { +function clearSource() { src = null; referenceMap = null; currentStructures = null; } -export function addExtension(extension) { +function addExtension(extension) { if (extension.unpack) currentExtensions[extension.type] = extension.unpack; else currentExtensions[extension.type] = extension; } -export const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding +const mult10 = new Array(147); for (let i = 0; i < 256; i++) { mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103)); } -export const Decoder = Unpackr; -var defaultUnpackr = new Unpackr({ useRecords: false }); +const defaultUnpackr = new Unpackr({ useRecords: false }); export const unpack = defaultUnpackr.unpack; -export const unpackMultiple = defaultUnpackr.unpackMultiple; -export const decode = defaultUnpackr.unpack; -export const FLOAT32_OPTIONS = { - NEVER: 0, - ALWAYS: 1, - DECIMAL_ROUND: 3, - DECIMAL_FIT: 4 -}; -const f32Array = new Float32Array(1); -const u8Array = new Uint8Array(f32Array.buffer, 0, 4); -export function roundFloat32(float32Number) { - f32Array[0] = float32Number; - const multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]; - return ( - ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / - multiplier - ); -} -export function setReadStruct(updatedReadStruct, loadedStructs, saveState) { - readStruct = updatedReadStruct; - onLoadedStructures = loadedStructs; - onSaveState = saveState; -}