nv-buf-serde ======================= - rewrite v8/src/objects/value-serializer.cc to JS - to let you use nodejs'v8.serialize AND nodejs'v8.deserialize in browser, - similiar to structuredClone AND MessageChannel-transfer, but can be used to send/recv
npm install nv-buf-serde
nv-buf-serde
=======================
- rewrite v8/src/objects/value-serializer.cc to JS
- to let you use nodejs'v8.serialize AND nodejs'v8.deserialize in browser,
- similiar to structuredClone AND MessageChannel-transfer, but can be used to send/recv data to server-side
- only work in 【BROWSER】 for transfering-with-remote-server:
- coz for local-transfer structuredClone is best(json'speed is best,but only support simple data-type);
- for 【server-side-remote-transfer】in nodejs you can use v8.serialize AND v8.deserialize directly;
- this is 【SLOW】, coz it is wrote in pure-js.
- only suited for 【SMALL-data such as complicated start-config】 with map/set/circular/array-buffer.... ,which only be transfered when app starting for one-time.
- see UNSUPPORTED below for unsupported data-type
- for most data-types,if data is small, its a little faster than v8.serialize/v8.deserilize in nodejs. coz it did NOT do any check/verify/validate
- but for string , its 10X slower , coz it read the string char-by-char to code-point.
- for not-small size array/object, its 5X slower.
- see SIMPLE-PERF below
install
=======
- npm install nv-buf-serde
usage
=====
//copy the dist.js in ./DIST to your browser
const { ser,der } = v8serde;
example
-------
ser(o:Any, version:Uint = 15) : ArrayBuffer; // version default is 15
// if server use node16 ,try 13.
// IF server nodejs ver < 16, this pkg maybe NOT work.
der(ab:ArrayBuffer) :
###
const {deepStrictEqual} = require("assert");
var st = new Set([])
for(let e of [1,1.1,undefined,null,true,false,"abcd","aÿ我𝑒",12345678901234567890n,[],{}]) {st.add(e)}
var mp = new Map();
let dict = {a:100,b:-0}
let ary = [0,1,2,3]
for(let e of [[{},[]],[true,false],[dict,dict],[ary,ary]]) {mp.set(e,e)}
for(let e of [[]]) {mp.set(e,e)}
for(let e of [1,1.1,undefined,null,true,false,"abcd","aÿ我𝑒",12345678901234567890n]) {mp.set(e,e)}
var circular = [];
circular[0] = circular
circular[1] = {pr:circular[0]}
circular[2] = mp
st.add(mp);
mp.set("set",st);
/*
> circular
[
[Circular *1],
{ pr: [Circular *1] },
Map(15) {
[ {}, [] ] => [ {}, [] ],
[ true, false ] => [ true, false ],
[ [Object], [Object] ] => [ [Object], [Object] ],
[ [Array], [Array] ] => [ [Array], [Array] ],
[] => [],
1 => 1,
1.1 => 1.1,
undefined => undefined,
null => null,
true => true,
false => false,
'abcd' => 'abcd',
'aÿ我𝑒' => 'aÿ我𝑒',
12345678901234567890n => 12345678901234567890n,
'set' => Set(12) {
1,
1.1,
undefined,
null,
true,
false,
'abcd',
'aÿ我𝑒',
12345678901234567890n,
[],
{},
[Circular *2]
}
}
]
>
*/
> var dump = ser(circular);
/*
> dump
ArrayBuffer {
[Uint8Contents]:
byteLength: 253
}
>
*/
var dupe = der(dump);
assert.deepStrictEqual(circular,dupe)
TEST
=====
cd ./TEST ./run.sh
f0 AND ff0 is v8.serialize/v8.deserialize
f1 AND ff1 is pure-js ser/der
####
w-1bstr.js
{ rounds: 100000, f: [Function: f0], costed: 266.1992090046406 }
{ rounds: 100000, f: [Function: f1], costed: 1591.1110320091248 }
w-2bstr.js
{ rounds: 100000, f: [Function: f0], costed: 228.52056899666786 }
{ rounds: 100000, f: [Function: f1], costed: 660.8281089961529 }
w-bi.js
{ rounds: 1000000, f: [Function: f0], costed: 1849.7178589999676 }
{ rounds: 1000000, f: [Function: f1], costed: 1643.9760229885578 }
w-double.js
{ rounds: 1, f: [Function: ff0], costed: 2050.589771002531 }
{ rounds: 1, f: [Function: ff1], costed: 1856.7536469995975 }
w-int-not-smi.js
{ rounds: 1, f: [Function: ff0], costed: 2139.468289002776 }
{ rounds: 1, f: [Function: ff1], costed: 1751.2041779905558 }
w-odd-ball.js
{ rounds: 1000000, f: [Function: f0], costed: 1801.9907419979572 }
{ rounds: 1000000, f: [Function: f1], costed: 742.1094769984484 }
{ rounds: 1000000, f: [Function: f0], costed: 1820.1971789896488 }
{ rounds: 1000000, f: [Function: f1], costed: 748.5948320031166 }
{ rounds: 1000000, f: [Function: f0], costed: 1815.4723690003157 }
{ rounds: 1000000, f: [Function: f1], costed: 760.0095049887896 }
{ rounds: 1000000, f: [Function: f0], costed: 1806.1364599913359 }
{ rounds: 1000000, f: [Function: f1], costed: 730.0119130015373 }
w-packed-double.js
{ rounds: 1, f: [Function: ff0], costed: 2115.820453003049 }
{ rounds: 1, f: [Function: ff1], costed: 1731.7947219908237 }
w-packed-smi.js
{ rounds: 1, f: [Function: ff0], costed: 1007.4265009909868 }
{ rounds: 1, f: [Function: ff1], costed: 389.41917300224304 }
w-prim-wrap.js
{ rounds: 100000, f: [Function: ff0], costed: 1601.2434429973364 }
{ rounds: 100000, f: [Function: ff1], costed: 638.7041679918766 }
w-smi.js
{ rounds: 1, f: [Function: ff0], costed: 2105.5412980020046 }
{ rounds: 1, f: [Function: ff1], costed: 950.825115993619 }
w-packed-with-attr.js
{ rounds: 1, f: [Function: ff0], costed: 1437.0307759940624 }
{ rounds: 1, f: [Function: ff1], costed: 740.9776969999075 }
w-ab-and-abvw.js
{ rounds: 1, f: [Function: ff0], costed: 3125.2701260000467 }
{ rounds: 1, f: [Function: ff1], costed: 1463.7843720018864 }
w-date.js
{ rounds: 100000, f: [Function: f0], costed: 378.10796700417995 }
{ rounds: 100000, f: [Function: f1], costed: 218.29990500211716 }
w-rgx.js
{ rounds: 100000, f: [Function: f0], costed: 360.65081399679184 }
{ rounds: 100000, f: [Function: f1], costed: 196.77194899320602 }
r-1bstr.js
OK
{ rounds: 1, f: [Function: ff0], costed: 622.7416110038757 }
{ rounds: 1, f: [Function: ff1], costed: 271.9350669980049 }
r-2bstr.js
OK
{ rounds: 1, f: [Function: ff0], costed: 136.93560498952866 }
{ rounds: 1, f: [Function: ff1], costed: 146.48304900527 }
r-bi.js
OK
{ rounds: 1, f: [Function: ff0], costed: 1521.1638139933348 }
{ rounds: 1, f: [Function: ff1], costed: 560.5311820060015 }
r-double.js
OK
{ rounds: 1, f: [Function: ff0], costed: 1761.6175539940596 }
{ rounds: 1, f: [Function: ff1], costed: 296.7176159918308 }
r-int-not-smi.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 2367.8616740107536 }
{ rounds: 1000000, f: [Function: ff1], costed: 451.3351549953222 }
r-odd-ball.js
OK
{ rounds: 1, f: [Function: ff0], costed: 1346.4026799947023 }
{ rounds: 1, f: [Function: ff1], costed: 240.1754889935255 }
r-packed-double.js
OK
{ rounds: 20, f: [Function: ff0], costed: 3246.5816289931536 }
{ rounds: 20, f: [Function: ff1], costed: 3989.6508100032806 }
r-packed-smi.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 1818.279228001833 }
{ rounds: 1000000, f: [Function: ff1], costed: 2230.154618009925 }
r-prim-wrap.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 7234.687916994095 }
{ rounds: 1000000, f: [Function: ff1], costed: 3035.835222005844 }
r-smi.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 6417.46975800395 }
{ rounds: 1000000, f: [Function: ff1], costed: 1456.2603430002928 }
r-packed-with-attr.js
OK
{ rounds: 20, f: [Function: ff0], costed: 1868.1501239985228 }
{ rounds: 20, f: [Function: ff1], costed: 7413.920781999826 }
r-ab-and-abvw.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 30922.769218996167 }
{ rounds: 1000000, f: [Function: ff1], costed: 22780.244821995497 }
r-date.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 2954.3600009977818 }
{ rounds: 1000000, f: [Function: ff1], costed: 1190.4288749992847 }
r-rgx.js
OK
{ rounds: 1000000, f: [Function: ff0], costed: 3780.0919840037823 }
{ rounds: 1000000, f: [Function: ff1], costed: 2295.3174780011177 }
r-mp-st-circular.js
OK
OK
OK
OK
OK
{ rounds: 2000, f: [Function: ff0], costed: 350.00537499785423 }
{ rounds: 2000, f: [Function: ff1], costed: 1388.989602997899 }
w-err.js
{ rounds: 1000000, f: [Function: f0], costed: 4555.216290995479 }
{ rounds: 1000000, f: [Function: f1], costed: 9781.851919993758 }
{ rounds: 1000000, f: [Function: f0], costed: 4957.54928599298 }
{ rounds: 1000000, f: [Function: f1], costed: 10075.762607008219 }
{ rounds: 1000000, f: [Function: f0], costed: 4710.144057005644 }
{ rounds: 1000000, f: [Function: f1], costed: 10048.256901994348 }
{ rounds: 1000000, f: [Function: f0], costed: 4756.645067989826 }
{ rounds: 1000000, f: [Function: f1], costed: 10162.962930992246 }
{ rounds: 1000000, f: [Function: f0], costed: 4752.813621997833 }
{ rounds: 1000000, f: [Function: f1], costed: 10042.401304006577 }
{ rounds: 1000000, f: [Function: f0], costed: 4700.770161986351 }
{ rounds: 1000000, f: [Function: f1], costed: 10009.027477994561 }
r-err.js
OK
{ rounds: 1, f: [Function: ff0], costed: 1471.0474539995193 }
{ rounds: 1, f: [Function: ff1], costed: 207.64260099828243 }
METHODS
========
- too many, most are USELESS , just use ser/der AND refer to const is OK.
APIS
=======
{
////-----------------------------------------------------------
fixed_cfg : _fixed_cfg, // v8flag compatible to nodejs
restrict : _restrict, // unsupported data-type readme
const : _const, // tag AND subtag(for array-buffer-view) definition
misc : _misc, // some int AND str util
zero_nid : _zero_nid, // v8 impl require ref-id from 0
ctx : _ctx, // context (for handle circular reference)
w : _w, // encode methods
r : _r, // decode methods
////----------------------------------------------------------------------
ser, // serialize USED on sender-side
der, // deserialize USED on recver-side
}
RESTRICT
=========
const restrict = require("nv-buf-serde").restrict;
console.dir(restrict,{depth:null})
/*
{
////----- roughly support
kTheHole : ,
the hole element will be replaced by undefined,coz in js-layer:
1. when serialize: the-hole-element can only be founded using .foreach, and that is expensive.
2. when deser : need use trick like { var a=[]; a[8] = 9;} to make the-hole, also expensive.
kSparseArray : ,
NOT support. only dense/packed_smi/packed_double.
hard to explain this, refer to ./TEST/hole-tst.js
this script will make sparse-array
kSharedArrayBuffer : ,
treated as normal ArrayBuffer,
although v8 has the code for this routing, but it failed when i test,
dont known how to find shared-array-buffer-id
kArrayBufferView :
0. array-buffer-view will be treated as kHostObject,for compatible with nodejes delegate(although its implement MAYBE wrong),
event if several array-buf-views refer to the same buffer, still be DEEP-COPIED:
var ab = new ArrayBuffer(4);
var u8a = new Uint8Array(ab);
var u16a = new Uint16Array(ab);
var ary = [ab,u8a,u16a];
var dupe_ary = der(ser(ary));
/*
1. dupe_ary[0]
2. dupe_ary[1].buffer
3. dupe_ary[2].buffer
[1. 2. 3.] are different buffer, this means:
the abview NOT support keeping the ref-of-<.buffer>-relations
*/
,
JSMap : "extra attributes set On Map will be dropped, for compatible to current v8-impl",
JSSet : "extra attributes set On Set will be dropped, for compatible to current v8-impl",
RegExp : "extra attributes set On RegExp will be dropped, for compatible to current v8-impl",
Date : "extra attributes set On Date will be dropped, for compatible to current v8-impl",
PrimitiveWrapper : ,
extra attributes set On PrimitiveWrapper will be dropped(treat-as-leaf), for compatible to current v8-impl;
not support
////------partly support:
"Error'message" : "Error'message treated as string",
"Error'stack" : "Error'stack treated as string",
////----- unsupported:
kVerifyObjectCount : "no verify",
throwDetachedArrayBufferError : "dont know how to get this state in js-layer",
kArrayBufferTransfer : "hard to do this in js-layer",
kSharedObject : 'hard to do this in js-layer',
kWasmModuleTransfer : 'hard to do this in js-layer',
kWasmMemoryTransfer : 'hard to do this in js-layer',
ITERATOR : "dont know how to get the iter cursor in js-layer, treated as a {}",
ATOMICS : "dont know how to do this, treated as a {}",
FPG : "function | lambda | promise| generator| all treated as a {}",
Proxy : "hard to do this in browser, so treated as the-target-be-proxied",
}
*/
APPENDIX
========
this pkg JUST for test backword-serde in nvlang. NOT for production.
70% syntax in nvlang is same as JS :
(es3 + await + Destructuring-assignment + getter-setter-only-class(similar to pod struct)) + a little TS(just-used-as-comments)
the lefted 30% is a graph-dsl.
LICENSE
=======
- ISC