Last active
June 12, 2023 08:34
-
-
Save SwadicalRag/c7d862a6bcebd2872d7f98bff4bd87b7 to your computer and use it in GitHub Desktop.
Obj2Obj for message passing between electron/node
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @typedef {(EncodedValue|EncodedDate|EncodedArray|EncodedMap|EncodedSet|EncodedObject|EncodedReference)} EncodedObj | |
*/ | |
/** | |
* @typedef {{type: "string"|"number"|"boolean"|"undefined", val: string|number|boolean|undefined}} EncodedValue | |
*/ | |
/** | |
* @typedef {{type: "date", val: string, ref: number}} EncodedDate | |
*/ | |
/** | |
* @typedef {{type: "array", val: EncodedObj[], ref: number}} EncodedArray | |
*/ | |
/** | |
* @typedef {{type: "map", val: {key: EncodedObj, val: EncodedObj}[], ref: number}} EncodedMap | |
*/ | |
/** | |
* @typedef {{type: "set", val: EncodedObj[], ref: number}} EncodedSet | |
*/ | |
/** | |
* @typedef {{type: "object", val: {key: string, val: EncodedObj}[], ref: number}} EncodedObject | |
*/ | |
/** | |
* @typedef {{type: "ref", val: number}} EncodedReference | |
*/ | |
class Obj2Obj { | |
/** | |
* Encodes any object into an EncodedObj. | |
* @param {*} obj - The object to encode. | |
* @param {Map<*, number>=} refs - The reference map. | |
* @param {Set<*>=} blocklist - Entities to omit during encoding. | |
* @return {EncodedObj} - The encoded object. | |
*/ | |
static Encode(obj, refs, blocklist) { | |
const typeID = typeof obj; | |
refs = refs || new Map(); | |
// different encoding strategies depending on the object type | |
if(typeID === "object") { | |
if(blocklist && blocklist.has(obj)) { | |
return {type: "undefined",val: undefined}; | |
} | |
else if(refs.has(obj)) { | |
return { | |
type: "ref", | |
val: refs.get(obj), | |
} | |
} | |
else if(Array.isArray(obj)) { | |
let out = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let val of obj) { | |
out.push(this.Encode(val,refs,blocklist)); | |
} | |
return { | |
type: "array", | |
val: out, | |
ref, | |
} | |
} | |
else if(obj instanceof Date) { | |
let ref = refs.size; | |
refs.set(obj,ref); | |
return { | |
type: "date", | |
val: obj.toISOString(), | |
ref, | |
} | |
} | |
else if(obj instanceof Map) { | |
let out = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let [key,val] of obj) { | |
out.push({ | |
key: this.Encode(key,refs,blocklist), | |
val: this.Encode(val,refs,blocklist), | |
}); | |
} | |
return { | |
type: "map", | |
val: out, | |
ref, | |
} | |
} | |
else if(obj instanceof Set) { | |
let out = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let val of obj) { | |
out.push(this.Encode(val,refs,blocklist)); | |
} | |
return { | |
type: "set", | |
val: out, | |
ref, | |
} | |
} | |
else { | |
let out = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let key in obj) { | |
out.push({ | |
key: key, | |
val: this.Encode(obj[key],refs,blocklist), | |
}); | |
} | |
return { | |
type: "object", | |
val: out, | |
ref, | |
} | |
} | |
} | |
else if(typeID === "symbol" || typeID === "function" || typeID === "bigint") { | |
return {type: "undefined", val: undefined}; | |
} | |
else { | |
// encoding for string, number, boolean and undefined types | |
return { | |
type: typeID, | |
val: obj, | |
}; | |
} | |
} | |
/** | |
* Decodes an EncodedObj into its original form. | |
* @param {EncodedObj} obj - The EncodedObj to decode. | |
* @param {Map<number, *>=} refs - The reference map. | |
* @return {*} - The decoded object. | |
*/ | |
static Decode(obj, refs) { | |
refs = refs || new Map(); | |
// different decoding strategies depending on the EncodedObj type | |
switch(obj.type) { | |
case "array": { | |
let out = []; | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out.push(this.Decode(entry,refs)); | |
} | |
return out; | |
} | |
case "date": { | |
let out = new Date(obj.val); | |
refs.set(obj.ref,out); | |
return out; | |
} | |
case "map": { | |
let out = new Map(); | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out.set(this.Decode(entry.key,refs),this.Decode(entry.val,refs)); | |
} | |
return out; | |
} | |
case "object": { | |
let out = {}; | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out[entry.key] = this.Decode(entry.val,refs); | |
} | |
return out; | |
} | |
case "ref": { | |
return refs.get(obj.val); | |
} | |
case "set": { | |
let out = new Set(); | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out.add(this.Decode(entry,refs)); | |
} | |
return out; | |
} | |
default: { | |
// decoding for value types | |
return obj.val; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface EncodedValue { | |
type: "string" | "number" | "boolean" | "undefined"; | |
val: string | number | boolean | undefined; | |
} | |
interface EncodedDate { | |
type: "date"; | |
val: string; | |
ref: number; | |
} | |
interface EncodedArray { | |
type: "array"; | |
val: EncodedObj[]; | |
ref: number; | |
} | |
interface EncodedMap { | |
type: "map"; | |
val: {key: EncodedObj, val: EncodedObj}[]; | |
ref: number; | |
} | |
interface EncodedSet { | |
type: "set"; | |
val: EncodedObj[]; | |
ref: number; | |
} | |
interface EncodedObject { | |
type: "object"; | |
val: {key: string, val: EncodedObj}[]; | |
ref: number; | |
} | |
interface EncodedReference { | |
type: "ref"; | |
val: number; | |
} | |
export type EncodedObj = EncodedValue | EncodedDate | EncodedArray | EncodedMap | EncodedSet | EncodedObject | EncodedReference; | |
export class Obj2Obj { | |
static Encode(obj: any, refs?: Map<any, number>, blocklist?: Set<any>): EncodedObj { | |
const typeID = typeof obj; | |
refs = refs ?? new Map(); | |
if(typeID === "object") { | |
if(blocklist && blocklist.has(obj)) { | |
return {type: "undefined",val: undefined}; | |
} | |
else if(refs.has(obj)) { | |
return { | |
type: "ref", | |
val: refs.get(obj)!, | |
} | |
} | |
else if(Array.isArray(obj)) { | |
let out: EncodedArray["val"] = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let val of obj) { | |
out.push(this.Encode(val,refs,blocklist)); | |
} | |
return { | |
type: "array", | |
val: out, | |
ref, | |
} | |
} | |
else if(obj instanceof Date) { | |
let ref = refs.size; | |
refs.set(obj,ref); | |
return { | |
type: "date", | |
val: obj.toISOString(), | |
ref, | |
} | |
} | |
else if(obj instanceof Map) { | |
let out: EncodedMap["val"] = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let [key,val] of obj) { | |
out.push({ | |
key: this.Encode(key,refs,blocklist), | |
val: this.Encode(val,refs,blocklist), | |
}); | |
} | |
return { | |
type: "map", | |
val: out, | |
ref, | |
} | |
} | |
else if(obj instanceof Set) { | |
let out = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let val of obj) { | |
out.push(this.Encode(val,refs,blocklist)); | |
} | |
return { | |
type: "set", | |
val: out, | |
ref, | |
} | |
} | |
else { | |
let out: EncodedObject["val"] = []; | |
let ref = refs.size; | |
refs.set(obj,ref); | |
for(let key in obj) { | |
out.push({ | |
key: key, | |
val: this.Encode(obj[key],refs,blocklist), | |
}); | |
} | |
return { | |
type: "object", | |
val: out, | |
ref, | |
} | |
} | |
} | |
else if(typeID === "symbol") { | |
return {type: "undefined", val: undefined}; | |
} | |
else if(typeID === "function") { | |
return {type: "undefined", val: undefined}; | |
} | |
else if(typeID === "bigint") { | |
return {type: "undefined", val: undefined}; | |
} | |
else { | |
return { | |
type: typeID, | |
val: obj, | |
}; | |
} | |
} | |
static Decode(obj: EncodedObj, refs?: Map<number, any>): any { | |
refs = refs ?? new Map(); | |
switch(obj.type) { | |
case "array": { | |
let out: any[] = []; | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out.push(this.Decode(entry,refs)); | |
} | |
return out; | |
} | |
case "date": { | |
let out = new Date(obj.val); | |
refs.set(obj.ref,out); | |
return out; | |
} | |
case "map": { | |
let out = new Map(); | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out.set(this.Decode(entry.key,refs),this.Decode(entry.val,refs)); | |
} | |
return out; | |
} | |
case "object": { | |
let out: any = {}; | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out[entry.key] = this.Decode(entry.val,refs); | |
} | |
return out; | |
} | |
case "ref": { | |
return refs.get(obj.val)!; | |
} | |
case "set": { | |
let out = new Set(); | |
refs.set(obj.ref,out); | |
for(let entry of obj.val) { | |
out.add(this.Decode(entry,refs)); | |
} | |
return out; | |
} | |
default: { | |
return obj.val; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment