// Note: this uses Node.js' `Buffer`, so it might not work in the browser // You can use a polyfill or write yours. const RED = [0xFF, 0, 0, 0xFF]; // R, G, B, A const GREEN = [0, 0xFF, 0, 0xFF]; function serialize(val, outputBytes = []) { if (typeof val === "string") { serializeString(val, outputBytes); } else { serializeObject(val, outputBytes); } return outputBytes; } function wrapInRGBA(value) { const rgba = [0, 0, 0, 255]; const indexToUse = Math.floor(Math.random() * 3); rgba[indexToUse] = value; return rgba; } function serializeObject(obj, outputBytes = []) { const keys = Object.keys(obj); outputBytes.push(...RED); outputBytes.push(...wrapInRGBA(keys.length)); keys.forEach((key) => { serialize(key, outputBytes); serialize(obj[key], outputBytes); }); return outputBytes; } function serializeString(str, outputBytes = []) { outputBytes.push(...GREEN); outputBytes.push(...wrapInRGBA(str.length)); for (let i = 0; i < str.length; i++) { outputBytes.push(...wrapInRGBA(str.charCodeAt(i))); } return outputBytes; } function parseFromString(serializedString) { return Buffer.from(serializedString, "hex"); } function deserialize(buffer, start = 0) { let original; let [type, nextIndex] = getNextFourBytes(buffer, start); if (Array.from(type).toString() === RED.toString()) { original = {}; let keyCount; [keyCount, nextIndex] = getTruthByte(buffer, nextIndex); while (keyCount--) { let key, value; [key, nextIndex] = deserialize(buffer, nextIndex); [value, nextIndex] = deserialize(buffer, nextIndex); original[key] = value; } } else if (Array.from(type).toString() === GREEN.toString()) { let length; [length, nextIndex] = getTruthByte(buffer, nextIndex); const characters = []; for (let i = 0; i < length; i++) { [character, nextIndex] = getTruthByte(buffer, nextIndex); characters.push(character); } original = characters.map(v => String.fromCharCode(v)).join(""); } return [original, nextIndex]; } function getNextFourBytes(buffer, start) { return [buffer.slice(start, start + 4), start + 4]; } function getTruthByte(buffer, start) { const [slice, nextIndex] = getNextFourBytes(buffer, start); return [Array.from(slice).find(v => v != 0) || 0, nextIndex]; } const obj = {hello: {nested: {nested: "world"}}}; const serialized = serialize(obj); console.log(serialized); const {Buffer} = require("buffer"); const serializedString = Buffer.from(serialized).toString("hex"); console.log(serializedString); console.log(Buffer.from(serialized).toString("utf8")); const buffer = parseFromString(serializedString); const [deserialized] = deserialize(buffer); console.log(deserialized);