Comparing version 0.8.3 to 0.9.0
@@ -838,3 +838,3 @@ "use strict" | ||
export let mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding | ||
export const mult10 = new Array(147) // this is a table matching binary exponents to the multiplier to determine significant digit rounding | ||
for (let i = 0; i < 256; i++) { | ||
@@ -854,1 +854,8 @@ mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103)) | ||
} | ||
let f32Array = new Float32Array(1) | ||
let u8Array = new Uint8Array(f32Array.buffer, 0, 4) | ||
export function roundFloat32(float32Number) { | ||
f32Array[0] = float32Number | ||
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)] | ||
return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier | ||
} |
@@ -783,3 +783,3 @@ (function (global, factory) { | ||
let mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding | ||
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding | ||
for (let i = 0; i < 256; i++) { | ||
@@ -797,2 +797,9 @@ mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103)); | ||
}; | ||
let f32Array = new Float32Array(1); | ||
let u8Array = new Uint8Array(f32Array.buffer, 0, 4); | ||
function roundFloat32(float32Number) { | ||
f32Array[0] = float32Number; | ||
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]; | ||
return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier | ||
} | ||
@@ -842,7 +849,4 @@ let textEncoder; | ||
let serializationsSinceTransitionRebuild = 0; | ||
if (this.structures && this.structures.length > maxSharedStructures) { | ||
throw new Error('Too many shared structures') | ||
} | ||
this.encode = function(value) { | ||
this.encode = function(value, encodeOptions) { | ||
if (!target) { | ||
@@ -860,3 +864,4 @@ target = new ByteArrayAllocate(8192); | ||
position$1 = 0; | ||
} | ||
} else if (encodeOptions === REUSE_BUFFER_MODE) | ||
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster | ||
start = position$1; | ||
@@ -869,3 +874,3 @@ referenceMap = encoder.structuredClone ? new Map() : null; | ||
let sharedStructuresLength = sharedStructures.length; | ||
if (sharedStructuresLength > maxSharedStructures && !isSequential) | ||
if (sharedStructuresLength > maxSharedStructures && !isSequential) | ||
sharedStructuresLength = maxSharedStructures; | ||
@@ -880,4 +885,4 @@ if (!sharedStructures.transitions) { | ||
let nextTransition, transition = sharedStructures.transitions; | ||
for (let i =0, l = keys.length; i < l; i++) { | ||
let key = keys[i]; | ||
for (let j = 0, l = keys.length; j < l; j++) { | ||
let key = keys[j]; | ||
nextTransition = transition[key]; | ||
@@ -911,3 +916,8 @@ if (!nextTransition) { | ||
} | ||
return target.subarray(start, position$1) // position can change if we call encode again in saveStructures, so we get the buffer now | ||
if (encodeOptions === REUSE_BUFFER_MODE) { | ||
target.start = start; | ||
target.end = position$1; | ||
return target | ||
} | ||
return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now | ||
} finally { | ||
@@ -934,3 +944,4 @@ if (sharedStructures) { | ||
} | ||
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save | ||
let returnBuffer = target.subarray(start, position$1); | ||
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) { | ||
@@ -942,2 +953,3 @@ // get updated structures and try again if the update failed | ||
lastSharedStructuresLength = encoder.structures.length; | ||
return returnBuffer | ||
} | ||
@@ -1063,3 +1075,3 @@ } | ||
if (useFloat32 < 4 || | ||
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved | ||
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved | ||
((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) { | ||
@@ -1195,3 +1207,3 @@ position$1 += 4; | ||
} else { | ||
throw new Error('Unknown type ' + type) | ||
throw new Error('Unknown type: ' + type) | ||
} | ||
@@ -1285,3 +1297,3 @@ }; | ||
let length = keys.length; | ||
for (let i =0; i < length; i++) { | ||
for (let i = 0; i < length; i++) { | ||
let key = keys[i]; | ||
@@ -1521,2 +1533,3 @@ nextTransition = transition[key]; | ||
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS; | ||
const REUSE_BUFFER_MODE = 1000; | ||
@@ -1625,2 +1638,3 @@ /** | ||
exports.mapsAsObjects = mapsAsObjects; | ||
exports.roundFloat32 = roundFloat32; | ||
exports.useRecords = useRecords; | ||
@@ -1627,0 +1641,0 @@ |
@@ -32,5 +32,5 @@ (function(a,b){"object"==typeof exports&&"undefined"!=typeof module?b(exports):"function"==typeof define&&define.amd?define(["exports"],b):(a=a||self,b(a.CBOR={}))})(this,function(a){'use strict';function b(){try{let a=c();if(z==y)// finished reading this source, cleanup references | ||
let l=16>a?h(a):g(a);return null==l?e.string=P(a):e.string=l}function l(a,b){K[b]=b=>{if(!a)throw new Error("Could not find typed array for code "+typeCode);// we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned | ||
return new T[a](Uint8Array.prototype.slice.call(b,0).buffer)}}function m(a){let b=y,c=z,d=I,e=J,f=D,g=E,h=new Uint8Array(x.slice(0,y)),i=C,j=H,k=M,l=a();return y=b,z=c,I=d,J=e,D=f,E=g,x=h,M=k,C=i,H=j,F=new DataView(x.buffer,x.byteOffset,x.byteLength),l}function n(){x=null,E=null,C=null}function o(a){K[a.tag]=a.decode}function p(a){256>a?(ja[ma++]=152,ja[ma++]=a):65536>a?(ja[ma++]=153,ja[ma++]=a>>8,ja[ma++]=255&a):(ja[ma++]=154,ka.setUint32(ma,a),ma+=4)}function q(a){return{tag:a,encode:function(a,b){let c=a.byteLength,d=a.byteOffset||0,e=a.buffer||a;b(da?Buffer.from(e,d,c):new Uint8Array(e,d,c))}}}function r(a,b){let c=a.byteLength;24>c?ja[ma++]=64+c:256>c?(ja[ma++]=88,ja[ma++]=c):65536>c?(ja[ma++]=89,ja[ma++]=c>>8,ja[ma++]=255&c):(ja[ma++]=90,ka.setUint32(ma,c),ma+=4),ma+c>=ja.length&&b(ma+c),ja.set(a,ma),ma+=c}function s(a,b){// insert the ids that need to be referenced for structured clones | ||
return new T[a](Uint8Array.prototype.slice.call(b,0).buffer)}}function m(a){let b=y,c=z,d=I,e=J,f=D,g=E,h=new Uint8Array(x.slice(0,y)),i=C,j=H,k=M,l=a();return y=b,z=c,I=d,J=e,D=f,E=g,x=h,M=k,C=i,H=j,F=new DataView(x.buffer,x.byteOffset,x.byteLength),l}function n(){x=null,E=null,C=null}function o(a){K[a.tag]=a.decode}function p(a){256>a?(la[oa++]=152,la[oa++]=a):65536>a?(la[oa++]=153,la[oa++]=a>>8,la[oa++]=255&a):(la[oa++]=154,ma.setUint32(oa,a),oa+=4)}function q(a){return{tag:a,encode:function(a,b){let c=a.byteLength,d=a.byteOffset||0,e=a.buffer||a;b(fa?Buffer.from(e,d,c):new Uint8Array(e,d,c))}}}function r(a,b){let c=a.byteLength;24>c?la[oa++]=64+c:256>c?(la[oa++]=88,la[oa++]=c):65536>c?(la[oa++]=89,la[oa++]=c>>8,la[oa++]=255&c):(la[oa++]=90,ma.setUint32(oa,c),oa+=4),oa+c>=la.length&&b(oa+c),la.set(a,oa),oa+=c}function s(a,b){// insert the ids that need to be referenced for structured clones | ||
let c,d=8*b.length,e=a.length-d;for(b.sort((c,a)=>c.offset>a.offset?1:-1);c=b.pop();){let b=c.offset,f=c.id;a.copyWithin(b+d,b,e),d-=8;let g=b+d;// uint32 | ||
a[g++]=217,a[g++]=156,a[g++]=73,a[g++]=26,a[g++]=f>>24,a[g++]=255&f>>16,a[g++]=255&f>>8,a[g++]=255&f,e=b}return a}function t(a){if(a.Class){if(!a.encode)throw new Error("Extension has no encode function");ca.unshift(a.Class),ba.unshift(a)}o(a)}function*u(a,b){const c=new oa(b);for(const d of a)yield c.encode(d)}async function*v(a,b){const c=new oa(b);for await(const d of a)yield c.encode(d)}/** | ||
a[g++]=217,a[g++]=156,a[g++]=73,a[g++]=26,a[g++]=f>>24,a[g++]=255&f>>16,a[g++]=255&f>>8,a[g++]=255&f,e=b}return a}function t(a){if(a.Class){if(!a.encode)throw new Error("Extension has no encode function");ea.unshift(a.Class),da.unshift(a)}o(a)}function*u(a,b){const c=new qa(b);for(const d of a)yield c.encode(d)}async function*v(a,b){const c=new qa(b);for await(const d of a)yield c.encode(d)}/** | ||
* Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects | ||
@@ -47,14 +47,15 @@ * Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator. | ||
},K[40010]=a=>{// pointer extension (for structured clones) | ||
let b=E.get(a);return b.used=!0,b.target},K[258]=a=>new Set(a),(K[259]=a=>(H.mapsAsObjects&&(H.mapsAsObjects=!1,G=!0),a())).handlesRead=!0;const V=["Uint8","Uint8Clamped","Uint16","Uint32","BigUint64","Int8","Int16","Int32","BigInt64","Float32","Float64"].map(a=>a+"Array"),W=[64,68,69,70,71,72,77,78,79,81,82];for(let b=0;b<V.length;b++)l(V[b],W[b]);let X=Array(147);// this is a table matching binary exponents to the multiplier to determine significant digit rounding | ||
for(let b=0;256>b;b++)X[b]=+("1e"+Math.floor(45.15-.30103*b));let Y=new N({useRecords:!1});const Z=Y.decode,$=Y.decodeMultiple,_={NEVER:0,ALWAYS:1,DECIMAL_ROUND:3,DECIMAL_FIT:4};let aa;try{aa=new TextEncoder}catch(a){}let ba,ca;const da="undefined"!=typeof Buffer,ea=da?Buffer.allocUnsafeSlow:Uint8Array,fa=da?Buffer:Uint8Array,ga=105,ha=256,ia=da?4294967296:2144337920;let ja,ka,la,ma=0;const na=Symbol("record-id");class oa extends N{constructor(a){super(a),this.offset=0;let b,c,d,e,f,g=0,h=fa.prototype.utf8Write?function(a,b,c){return ja.utf8Write(a,b,c)}:!!(aa&&aa.encodeInto)&&function(a,b){return aa.encodeInto(a,ja.subarray(b)).written},i=this,j=64,k=a&&a.sequential;k&&(j=0,this.structures=[]);let m=[],n=0,o=0;if(this.structures&&this.structures.length>j)throw new Error("Too many shared structures");this.encode=function(a){if(ja||(ja=new ea(8192),ka=new DataView(ja.buffer,0,8192),ma=0),la=ja.length-10,2048>la-ma&&(ja=new ea(ja.length),ka=new DataView(ja.buffer,0,ja.length),la=ja.length-10,ma=0),b=ma,f=i.structuredClone?new Map:null,c=i.structures,c){c.uninitialized&&(i.structures=c=i.getStructures());let a=c.length;if(a>j&&!k&&(a=j),!c.transitions){c.transitions=Object.create(null);for(let b,d=0;d<a;d++){if(b=c[d],!b)continue;let a,e=c.transitions;for(let c,d=0,f=b.length;d<f;d++)c=b[d],a=e[c],a||(a=e[c]=Object.create(null)),e=a;e[na]=d}g=c.length}k||(c.nextId=a)}d&&(d=!1),e=c||[];try{// update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially | ||
if(q(a),i.offset=ma,f&&f.idsToInsert){ma+=8*f.idsToInsert.length,ma>la&&t(ma),i.offset=ma;let a=s(ja.subarray(b,ma),f.idsToInsert);return f=null,a}return ja.subarray(b,ma);// position can change if we call encode again in saveStructures, so we get the buffer now | ||
}finally{if(c){if(10>o&&o++,1e4<n)c.transitions=null,o=0,n=0,0<m.length&&(m=[]);else if(0<m.length&&!k){for(let a=0,b=m.length;a<b;a++)m[a][na]=void 0;m=[]}if(d&&i.saveStructures){if(i.structures.length>j&&(i.structures=i.structures.slice(0,j)),!1===i.saveStructures(i.structures,g))return i.structures=i.getStructures()||[],i.encode(a);g=i.structures.length}}}};const q=a=>{ma>la&&(ja=t(ma));var c,d=typeof a;if("string"==d){let b,d=a.length;b=32>d?1:256>d?2:65536>d?3:5;let e=3*d;if(ma+e>la&&(ja=t(ma+e)),64>d||!h){let e,f,g,h=ma+b;for(e=0;e<d;e++)f=a.charCodeAt(e),128>f?ja[h++]=f:2048>f?(ja[h++]=192|f>>6,ja[h++]=128|63&f):55296==(64512&f)&&56320==(64512&(g=a.charCodeAt(e+1)))?(f=65536+((1023&f)<<10)+(1023&g),e++,ja[h++]=240|f>>18,ja[h++]=128|63&f>>12,ja[h++]=128|63&f>>6,ja[h++]=128|63&f):(ja[h++]=224|f>>12,ja[h++]=128|63&f>>6,ja[h++]=128|63&f);c=h-ma-b}else c=h(a,ma+b,e);24>c?ja[ma++]=96|c:256>c?(2>b&&ja.copyWithin(ma+2,ma+1,ma+1+c),ja[ma++]=120,ja[ma++]=c):65536>c?(3>b&&ja.copyWithin(ma+3,ma+2,ma+2+c),ja[ma++]=121,ja[ma++]=c>>8,ja[ma++]=255&c):(5>b&&ja.copyWithin(ma+5,ma+3,ma+3+c),ja[ma++]=122,ka.setUint32(ma,c),ma+=4),ma+=c}else if("number"===d){if(a>>>0===a)24>a?ja[ma++]=a:256>a?(ja[ma++]=24,ja[ma++]=a):65536>a?(ja[ma++]=25,ja[ma++]=a>>8,ja[ma++]=255&a):(ja[ma++]=26,ka.setUint32(ma,a),ma+=4);else if(a>>0===a)-24<=a?ja[ma++]=31-a:-256<=a?(ja[ma++]=56,ja[ma++]=~a):-65536<=a?(ja[ma++]=57,ka.setUint16(ma,~a),ma+=2):(ja[ma++]=58,ka.setUint32(ma,~a),ma+=4);else{let b;if(0<(b=this.useFloat32)&&4294967296>a&&-2147483648<=a){ja[ma++]=250,ka.setFloat32(ma,a);let c;if(4>b||// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved | ||
(c=a*X[(127&ja[ma])<<1|ja[ma+1]>>7])>>0===c)return void(ma+=4);// move back into position for writing a double | ||
ma--}ja[ma++]=251,ka.setFloat64(ma,a),ma+=8}}else if("object"===d){if(!a)ja[ma++]=246;else{if(f){let c=f.get(a);if(c){if(!c.id){let a=f.idsToInsert||(f.idsToInsert=[]);c.id=a.push(c)}return ja[ma++]=217,ja[ma++]=156,ja[ma++]=74,ja[ma++]=26,ka.setUint32(ma,c.id),void(ma+=4)}f.set(a,{offset:ma-b})}let d=a.constructor;if(d===Object)r(a,!0);else if(d===Array){c=a.length,24>c?ja[ma++]=128|c:p(c);for(let b=0;b<c;b++)q(a[b])}else if(d===Map){(this.mapsAsObjects?!1!==this.useTag259ForMaps:this.useTag259ForMaps)&&(ja[ma++]=217,ja[ma++]=1,ja[ma++]=3),c=a.size,24>c?ja[ma++]=160|c:256>c?(ja[ma++]=184,ja[ma++]=c):65536>c?(ja[ma++]=185,ja[ma++]=c>>8,ja[ma++]=255&c):(ja[ma++]=186,ka.setUint32(ma,c),ma+=4);for(let[b,c]of a)q(b),q(c)}else{for(let b,c=0,d=ba.length;c<d;c++)if(b=ca[c],a instanceof b){let b=ba[c],d=b.tag;return 24>d?ja[ma++]=192|d:256>d?(ja[ma++]=216,ja[ma++]=d):65536>d?(ja[ma++]=217,ja[ma++]=d>>8,ja[ma++]=255&d):-1<d&&(ja[ma++]=218,ka.setUint32(ma,d),ma+=4),void b.encode.call(this,a,q,t)}if(a[Symbol.iterator]){ja[ma++]=159;// indefinite length array | ||
let b=E.get(a);return b.used=!0,b.target},K[258]=a=>new Set(a),(K[259]=a=>(H.mapsAsObjects&&(H.mapsAsObjects=!1,G=!0),a())).handlesRead=!0;const V=["Uint8","Uint8Clamped","Uint16","Uint32","BigUint64","Int8","Int16","Int32","BigInt64","Float32","Float64"].map(a=>a+"Array"),W=[64,68,69,70,71,72,77,78,79,81,82];for(let b=0;b<V.length;b++)l(V[b],W[b]);const X=Array(147);// this is a table matching binary exponents to the multiplier to determine significant digit rounding | ||
for(let b=0;256>b;b++)X[b]=+("1e"+Math.floor(45.15-.30103*b));let Y=new N({useRecords:!1});const Z=Y.decode,$=Y.decodeMultiple,_={NEVER:0,ALWAYS:1,DECIMAL_ROUND:3,DECIMAL_FIT:4};let aa,ba=new Float32Array(1),ca=new Uint8Array(ba.buffer,0,4);try{aa=new TextEncoder}catch(a){}let da,ea;const fa="undefined"!=typeof Buffer,ga=fa?Buffer.allocUnsafeSlow:Uint8Array,ha=fa?Buffer:Uint8Array,ia=105,ja=256,ka=fa?4294967296:2144337920;let la,ma,na,oa=0;const pa=Symbol("record-id");class qa extends N{constructor(a){super(a),this.offset=0;let b,c,d,e,f,g=0,h=ha.prototype.utf8Write?function(a,b,c){return la.utf8Write(a,b,c)}:!!(aa&&aa.encodeInto)&&function(a,b){return aa.encodeInto(a,la.subarray(b)).written},i=this,j=64,k=a&&a.sequential;k&&(j=0,this.structures=[]);let m=[],n=0,o=0;this.encode=function(a,h){if(la||(la=new ga(8192),ma=new DataView(la.buffer,0,8192),oa=0),na=la.length-10,2048>na-oa?(la=new ga(la.length),ma=new DataView(la.buffer,0,la.length),na=la.length-10,oa=0):h===xa&&(oa=2147483640&oa+7),b=oa,f=i.structuredClone?new Map:null,c=i.structures,c){c.uninitialized&&(i.structures=c=i.getStructures());let a=c.length;if(a>j&&!k&&(a=j),!c.transitions){c.transitions=Object.create(null);for(let b,d=0;d<a;d++){if(b=c[d],!b)continue;let a,e=c.transitions;for(let c,d=0,f=b.length;d<f;d++)c=b[d],a=e[c],a||(a=e[c]=Object.create(null)),e=a;e[pa]=d}g=c.length}k||(c.nextId=a)}d&&(d=!1),e=c||[];try{// update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially | ||
if(q(a),i.offset=oa,f&&f.idsToInsert){oa+=8*f.idsToInsert.length,oa>na&&t(oa),i.offset=oa;let a=s(la.subarray(b,oa),f.idsToInsert);return f=null,a}return h===xa?(la.start=b,la.end=oa,la):la.subarray(b,oa);// position can change if we call pack again in saveStructures, so we get the buffer now | ||
}finally{if(c){if(10>o&&o++,1e4<n)c.transitions=null,o=0,n=0,0<m.length&&(m=[]);else if(0<m.length&&!k){for(let a=0,b=m.length;a<b;a++)m[a][pa]=void 0;m=[]}if(d&&i.saveStructures){i.structures.length>j&&(i.structures=i.structures.slice(0,j));// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save | ||
let c=la.subarray(b,oa);return!1===i.saveStructures(i.structures,g)?(i.structures=i.getStructures()||[],i.encode(a)):(g=i.structures.length,c)}}}};const q=a=>{oa>na&&(la=t(oa));var c,d=typeof a;if("string"==d){let b,d=a.length;b=32>d?1:256>d?2:65536>d?3:5;let e=3*d;if(oa+e>na&&(la=t(oa+e)),64>d||!h){let e,f,g,h=oa+b;for(e=0;e<d;e++)f=a.charCodeAt(e),128>f?la[h++]=f:2048>f?(la[h++]=192|f>>6,la[h++]=128|63&f):55296==(64512&f)&&56320==(64512&(g=a.charCodeAt(e+1)))?(f=65536+((1023&f)<<10)+(1023&g),e++,la[h++]=240|f>>18,la[h++]=128|63&f>>12,la[h++]=128|63&f>>6,la[h++]=128|63&f):(la[h++]=224|f>>12,la[h++]=128|63&f>>6,la[h++]=128|63&f);c=h-oa-b}else c=h(a,oa+b,e);24>c?la[oa++]=96|c:256>c?(2>b&&la.copyWithin(oa+2,oa+1,oa+1+c),la[oa++]=120,la[oa++]=c):65536>c?(3>b&&la.copyWithin(oa+3,oa+2,oa+2+c),la[oa++]=121,la[oa++]=c>>8,la[oa++]=255&c):(5>b&&la.copyWithin(oa+5,oa+3,oa+3+c),la[oa++]=122,ma.setUint32(oa,c),oa+=4),oa+=c}else if("number"===d){if(a>>>0===a)24>a?la[oa++]=a:256>a?(la[oa++]=24,la[oa++]=a):65536>a?(la[oa++]=25,la[oa++]=a>>8,la[oa++]=255&a):(la[oa++]=26,ma.setUint32(oa,a),oa+=4);else if(a>>0===a)-24<=a?la[oa++]=31-a:-256<=a?(la[oa++]=56,la[oa++]=~a):-65536<=a?(la[oa++]=57,ma.setUint16(oa,~a),oa+=2):(la[oa++]=58,ma.setUint32(oa,~a),oa+=4);else{let b;if(0<(b=this.useFloat32)&&4294967296>a&&-2147483648<=a){la[oa++]=250,ma.setFloat32(oa,a);let c;if(4>b||// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved | ||
(c=a*X[(127&la[oa])<<1|la[oa+1]>>7])>>0===c)return void(oa+=4);// move back into position for writing a double | ||
oa--}la[oa++]=251,ma.setFloat64(oa,a),oa+=8}}else if("object"===d){if(!a)la[oa++]=246;else{if(f){let c=f.get(a);if(c){if(!c.id){let a=f.idsToInsert||(f.idsToInsert=[]);c.id=a.push(c)}return la[oa++]=217,la[oa++]=156,la[oa++]=74,la[oa++]=26,ma.setUint32(oa,c.id),void(oa+=4)}f.set(a,{offset:oa-b})}let d=a.constructor;if(d===Object)r(a,!0);else if(d===Array){c=a.length,24>c?la[oa++]=128|c:p(c);for(let b=0;b<c;b++)q(a[b])}else if(d===Map){(this.mapsAsObjects?!1!==this.useTag259ForMaps:this.useTag259ForMaps)&&(la[oa++]=217,la[oa++]=1,la[oa++]=3),c=a.size,24>c?la[oa++]=160|c:256>c?(la[oa++]=184,la[oa++]=c):65536>c?(la[oa++]=185,la[oa++]=c>>8,la[oa++]=255&c):(la[oa++]=186,ma.setUint32(oa,c),oa+=4);for(let[b,c]of a)q(b),q(c)}else{for(let b,c=0,d=da.length;c<d;c++)if(b=ea[c],a instanceof b){let b=da[c],d=b.tag;return 24>d?la[oa++]=192|d:256>d?(la[oa++]=216,la[oa++]=d):65536>d?(la[oa++]=217,la[oa++]=d>>8,la[oa++]=255&d):-1<d&&(la[oa++]=218,ma.setUint32(oa,d),oa+=4),void b.encode.call(this,a,q,t)}if(a[Symbol.iterator]){la[oa++]=159;// indefinite length array | ||
for(let b of a)q(b);// stop-code | ||
return void(ja[ma++]=255)}// no extension found, write as object | ||
r(a,!a.hasOwnProperty)}}}else if("boolean"===d)ja[ma++]=a?245:244;else if("bigint"===d){if(a<BigInt(1)<<BigInt(64)&&0<=a)ja[ma++]=27,ka.setBigUint64(ma,a);else if(a>-(BigInt(1)<<BigInt(64))&&0>a)ja[ma++]=59,ka.setBigUint64(ma,-a-BigInt(1));else// overflow | ||
if(this.largeBigIntToFloat)ja[ma++]=251,ka.setFloat64(ma,+a);else throw new RangeError(a+" was too large to fit in CBOR 64-bit integer format, set largeBigIntToFloat to convert to float-64");ma+=8}else if("undefined"===d)ja[ma++]=247;else throw new Error("Unknown type "+d)},r=!1===this.useRecords?this.variableMapSize?a=>{// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects) | ||
let b=Object.keys(a),c=b.length;24>c?ja[ma++]=160|c:256>c?(ja[ma++]=184,ja[ma++]=c):65536>c?(ja[ma++]=185,ja[ma++]=c>>8,ja[ma++]=255&c):(ja[ma++]=186,ka.setUint32(ma,c),ma+=4);let d;for(let e=0;e<c;e++)q(d=b[e]),q(a[d])}:(a,c)=>{ja[ma++]=185;// always use map 16, so we can preallocate and set the length afterwards | ||
let d=ma-b;ma+=2;let e=0;for(let b in a)(c||a.hasOwnProperty(b))&&(q(b),q(a[b]),e++);ja[d++ +b]=e>>8,ja[d+b]=255&e}:/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster | ||
return void(la[oa++]=255)}// no extension found, write as object | ||
r(a,!a.hasOwnProperty)}}}else if("boolean"===d)la[oa++]=a?245:244;else if("bigint"===d){if(a<BigInt(1)<<BigInt(64)&&0<=a)la[oa++]=27,ma.setBigUint64(oa,a);else if(a>-(BigInt(1)<<BigInt(64))&&0>a)la[oa++]=59,ma.setBigUint64(oa,-a-BigInt(1));else// overflow | ||
if(this.largeBigIntToFloat)la[oa++]=251,ma.setFloat64(oa,+a);else throw new RangeError(a+" was too large to fit in CBOR 64-bit integer format, set largeBigIntToFloat to convert to float-64");oa+=8}else if("undefined"===d)la[oa++]=247;else throw new Error("Unknown type: "+d)},r=!1===this.useRecords?this.variableMapSize?a=>{// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects) | ||
let b=Object.keys(a),c=b.length;24>c?la[oa++]=160|c:256>c?(la[oa++]=184,la[oa++]=c):65536>c?(la[oa++]=185,la[oa++]=c>>8,la[oa++]=255&c):(la[oa++]=186,ma.setUint32(oa,c),oa+=4);let d;for(let e=0;e<c;e++)q(d=b[e]),q(a[d])}:(a,c)=>{la[oa++]=185;// always use map 16, so we can preallocate and set the length afterwards | ||
let d=oa-b;oa+=2;let e=0;for(let b in a)(c||a.hasOwnProperty(b))&&(q(b),q(a[b]),e++);la[d++ +b]=e>>8,la[d+b]=255&e}:/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster | ||
(object, safePrototype) => { | ||
@@ -98,15 +99,14 @@ let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null)) | ||
target[objectOffset + start] = id | ||
}*/a=>{let b,f=Object.keys(a),g=e.transitions||(e.transitions=Object.create(null)),h=0,k=f.length;for(let c,d=0;d<k;d++)c=f[d],b=g[c],b||(b=g[c]=Object.create(null),h++),g=b;let l=g[na];if(void 0!==l)// tag two byte | ||
ja[ma++]=217,ja[ma++]=ga,ja[ma++]=l;else if(l=e.nextId++,l||(l=0,e.nextId=1),l>=ha&&(e.nextId=(l=j)+1),g[na]=l,e[l]=f,c&&c.length<=j)// tag two byte | ||
}*/a=>{let b,f=Object.keys(a),g=e.transitions||(e.transitions=Object.create(null)),h=0,k=f.length;for(let c,d=0;d<k;d++)c=f[d],b=g[c],b||(b=g[c]=Object.create(null),h++),g=b;let l=g[pa];if(void 0!==l)// tag two byte | ||
la[oa++]=217,la[oa++]=ia,la[oa++]=l;else if(l=e.nextId++,l||(l=0,e.nextId=1),l>=ja&&(e.nextId=(l=j)+1),g[pa]=l,e[l]=f,c&&c.length<=j)// tag two byte | ||
// tag number | ||
ja[ma++]=217,ja[ma++]=ga,ja[ma++]=l,d=!0;else{ja[ma++]=216,ja[ma++]=ga,h&&(n+=o*h),m.length>=ha-j&&(m.shift()[na]=void 0),m.push(g),22>k?ja[ma++]=130+k:// array header, length of values + 2 | ||
p(k+2),q(f),ja[ma++]=25,ja[ma++]=ga,ja[ma++]=l;// now write the values | ||
for(let b=0;b<k;b++)q(a[f[b]]);return}24>k?ja[ma++]=128|k:p(k);for(let b=0;b<k;b++)q(a[f[b]])},t=a=>{var c=Math.min,d=Math.round,e=Math.max;let f;if(16777216<a){// special handling for really large buffers | ||
if(a-b>ia)throw new Error("Encoded buffer would be larger than maximum buffer size");f=c(ia,4096*d(e((a-b)*(67108864<a?1.25:2),16777216)/4096))}else// faster handling for smaller buffers | ||
f=(e(a-b<<2,ja.length-1)>>12)+1<<12;let g=new ea(f);return ka=new DataView(g.buffer,0,f),ja.copy?ja.copy(g,0,b,a):g.set(ja.slice(b,a)),ma-=b,b=0,la=g.length-10,ja=g}}useBuffer(a){// this means we are finished using our own buffer and we can write over it safely | ||
ja=a,ka=new DataView(ja.buffer,ja.byteOffset,ja.byteLength),ma=0}}ca=[Date,Set,Error,RegExp,ArrayBuffer,fa,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array,BigUint64Array,Int8Array,Int16Array,Int32Array,BigInt64Array,Float32Array,Float64Array],ba=[{tag:1,encode(a){let b=a.getTime()/1e3;(this.useTimestamp32||0===a.getMilliseconds())&&0<=b&&4294967296>b?(ja[ma++]=26,ka.setUint32(ma,b),ma+=4):(ja[ma++]=251,ka.setFloat64(ma,b),ma+=8)}},{tag:258,// https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md | ||
la[oa++]=217,la[oa++]=ia,la[oa++]=l,d=!0;else{la[oa++]=216,la[oa++]=ia,h&&(n+=o*h),m.length>=ja-j&&(m.shift()[pa]=void 0),m.push(g),22>k?la[oa++]=130+k:p(k+2),q(f),la[oa++]=25,la[oa++]=ia,la[oa++]=l;// now write the values | ||
for(let b=0;b<k;b++)q(a[f[b]]);return}24>k?la[oa++]=128|k:p(k);for(let b=0;b<k;b++)q(a[f[b]])},t=a=>{var c=Math.min,d=Math.round,e=Math.max;let f;if(16777216<a){// special handling for really large buffers | ||
if(a-b>ka)throw new Error("Encoded buffer would be larger than maximum buffer size");f=c(ka,4096*d(e((a-b)*(67108864<a?1.25:2),16777216)/4096))}else// faster handling for smaller buffers | ||
f=(e(a-b<<2,la.length-1)>>12)+1<<12;let g=new ga(f);return ma=new DataView(g.buffer,0,f),la.copy?la.copy(g,0,b,a):g.set(la.slice(b,a)),oa-=b,b=0,na=g.length-10,la=g}}useBuffer(a){// this means we are finished using our own buffer and we can write over it safely | ||
la=a,ma=new DataView(la.buffer,la.byteOffset,la.byteLength),oa=0}}ea=[Date,Set,Error,RegExp,ArrayBuffer,ha,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array,BigUint64Array,Int8Array,Int16Array,Int32Array,BigInt64Array,Float32Array,Float64Array],da=[{tag:1,encode(a){let b=a.getTime()/1e3;(this.useTimestamp32||0===a.getMilliseconds())&&0<=b&&4294967296>b?(la[oa++]=26,ma.setUint32(oa,b),oa+=4):(la[oa++]=251,ma.setFloat64(oa,b),oa+=8)}},{tag:258,// https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md | ||
encode(a,b){let c=Array.from(a);b(c)}},{tag:27,// http://cbor.schmorp.de/generic-object | ||
encode(a,b){b([a.name,a.message])}},{tag:27,// http://cbor.schmorp.de/generic-object | ||
encode(a,b){b(["RegExp",a.source,a.flags])}},{encode(a,b,c){r(a,c)}},{encode(a,b,c){r(a,c)}},q(64),q(68),q(69),q(70),q(71),q(72),q(77),q(78),q(79),q(81),q(82)];let pa=new oa({useRecords:!1});const qa=pa.encode,{NEVER:ra,ALWAYS:sa,DECIMAL_ROUND:ta,DECIMAL_FIT:ua}=_;a.ALWAYS=sa,a.DECIMAL_FIT=ua,a.DECIMAL_ROUND=ta,a.Decoder=N,a.Encoder=oa,a.FLOAT32_OPTIONS=_,a.NEVER=ra,a.Tag=S,a.addExtension=t,a.clearSource=n,a.decode=Z,a.decodeIter=function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise");const c=new N(b);let d;const e=a=>{let b;// if there's incomplete data from previous chunk, concatinate and try again | ||
d&&(a=Buffer.concat([d,a]),d=void 0);try{b=c.decodeMultiple(a)}catch(c){if(c.incomplete)d=a.slice(c.lastPosition),b=c.values;else throw c}return b};if("function"==typeof a[Symbol.iterator])return function*(){for(const b of a)yield*e(b)}();return"function"==typeof a[Symbol.asyncIterator]?async function*(){for await(const b of a)yield*e(b)}():void 0},a.decodeMultiple=$,a.encode=qa,a.encodeIter=/** | ||
encode(a,b){b(["RegExp",a.source,a.flags])}},{encode(a,b,c){r(a,c)}},{encode(a,b,c){r(a,c)}},q(64),q(68),q(69),q(70),q(71),q(72),q(77),q(78),q(79),q(81),q(82)];let ra=new qa({useRecords:!1});const sa=ra.encode,{NEVER:ta,ALWAYS:ua,DECIMAL_ROUND:va,DECIMAL_FIT:wa}=_,xa=1e3;a.ALWAYS=ua,a.DECIMAL_FIT=wa,a.DECIMAL_ROUND=va,a.Decoder=N,a.Encoder=qa,a.FLOAT32_OPTIONS=_,a.NEVER=ta,a.Tag=S,a.addExtension=t,a.clearSource=n,a.decode=Z,a.decodeIter=function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise");const c=new N(b);let d;const e=a=>{let b;// if there's incomplete data from previous chunk, concatinate and try again | ||
d&&(a=Buffer.concat([d,a]),d=void 0);try{b=c.decodeMultiple(a)}catch(c){if(c.incomplete)d=a.slice(c.lastPosition),b=c.values;else throw c}return b};if("function"==typeof a[Symbol.iterator])return function*(){for(const b of a)yield*e(b)}();return"function"==typeof a[Symbol.asyncIterator]?async function*(){for await(const b of a)yield*e(b)}():void 0},a.decodeMultiple=$,a.encode=sa,a.encodeIter=/** | ||
* Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer | ||
@@ -117,2 +117,2 @@ * If the argument is only Async Iterable, the return value will be an Async Iterable. | ||
* @returns {IterableIterator|Promise.<AsyncIterableIterator>} | ||
*/function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable");else{if("function"==typeof a[Symbol.iterator])return u(a,b);if("function"==typeof a.then||"function"==typeof a[Symbol.asyncIterator])return v(a,b);throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise")}},a.mapsAsObjects=!0,a.useRecords=!1,Object.defineProperty(a,"__esModule",{value:!0})}); | ||
*/function(a,b={}){if(!a||"object"!=typeof a)throw new Error("first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable");else{if("function"==typeof a[Symbol.iterator])return u(a,b);if("function"==typeof a.then||"function"==typeof a[Symbol.asyncIterator])return v(a,b);throw new Error("first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise")}},a.mapsAsObjects=!0,a.roundFloat32=function(a){ba[0]=a;let b=X[(127&ca[3])<<1|ca[2]>>7];return(b*a+(0<a?.5:-.5)>>0)/b},a.useRecords=!1,Object.defineProperty(a,"__esModule",{value:!0})}); |
@@ -662,2 +662,9 @@ (function (CBOR, chai) { | ||
test('255 chars', function() { | ||
const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W'; | ||
var serialized = CBOR.encode(data); | ||
var deserialized = CBOR.decode(serialized); | ||
assert.equal(deserialized, data); | ||
}); | ||
test('encode/decode sample data', function(){ | ||
@@ -664,0 +671,0 @@ var data = sampleData; |
@@ -46,7 +46,4 @@ import { Decoder, mult10, Tag, typedArrays, addExtension as decodeAddExtension } from './decode.js' | ||
let serializationsSinceTransitionRebuild = 0 | ||
if (this.structures && this.structures.length > maxSharedStructures) { | ||
throw new Error('Too many shared structures') | ||
} | ||
this.encode = function(value) { | ||
this.encode = function(value, encodeOptions) { | ||
if (!target) { | ||
@@ -64,3 +61,4 @@ target = new ByteArrayAllocate(8192) | ||
position = 0 | ||
} | ||
} else if (encodeOptions === REUSE_BUFFER_MODE) | ||
position = (position + 7) & 0x7ffffff8 // Word align to make any future copying of this buffer faster | ||
start = position | ||
@@ -73,3 +71,3 @@ referenceMap = encoder.structuredClone ? new Map() : null | ||
let sharedStructuresLength = sharedStructures.length | ||
if (sharedStructuresLength > maxSharedStructures && !isSequential) | ||
if (sharedStructuresLength > maxSharedStructures && !isSequential) | ||
sharedStructuresLength = maxSharedStructures | ||
@@ -84,4 +82,4 @@ if (!sharedStructures.transitions) { | ||
let nextTransition, transition = sharedStructures.transitions | ||
for (let i =0, l = keys.length; i < l; i++) { | ||
let key = keys[i] | ||
for (let j = 0, l = keys.length; j < l; j++) { | ||
let key = keys[j] | ||
nextTransition = transition[key] | ||
@@ -115,3 +113,8 @@ if (!nextTransition) { | ||
} | ||
return target.subarray(start, position) // position can change if we call encode again in saveStructures, so we get the buffer now | ||
if (encodeOptions === REUSE_BUFFER_MODE) { | ||
target.start = start | ||
target.end = position | ||
return target | ||
} | ||
return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now | ||
} finally { | ||
@@ -138,3 +141,4 @@ if (sharedStructures) { | ||
} | ||
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save | ||
let returnBuffer = target.subarray(start, position) | ||
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) { | ||
@@ -146,2 +150,3 @@ // get updated structures and try again if the update failed | ||
lastSharedStructuresLength = encoder.structures.length | ||
return returnBuffer | ||
} | ||
@@ -267,3 +272,3 @@ } | ||
if (useFloat32 < 4 || | ||
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved | ||
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved | ||
((xShifted = value * mult10[((target[position] & 0x7f) << 1) | (target[position + 1] >> 7)]) >> 0) === xShifted) { | ||
@@ -399,3 +404,3 @@ position += 4 | ||
} else { | ||
throw new Error('Unknown type ' + type) | ||
throw new Error('Unknown type: ' + type) | ||
} | ||
@@ -489,3 +494,3 @@ } | ||
let length = keys.length | ||
for (let i =0; i < length; i++) { | ||
for (let i = 0; i < length; i++) { | ||
let key = keys[i] | ||
@@ -733,1 +738,2 @@ nextTransition = transition[key] | ||
export const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS | ||
export const REUSE_BUFFER_MODE = 1000 |
@@ -1,10 +0,11 @@ | ||
export { Decoder, decode, addExtension, FLOAT32_OPTIONS, clearSource } from './decode.js' | ||
export { Decoder, decode, addExtension, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './decode.js' | ||
export { Encoder, encode } from './encode.js' | ||
import { Transform, Readable } from 'stream' | ||
export as namespace CBOR; | ||
export class DecoderStream { | ||
export class DecoderStream extends Transform { | ||
constructor(options?: Options | { highWaterMark: number, emitClose: boolean, allowHalfOpen: boolean }) | ||
} | ||
export class EncoderStream { | ||
write(value: any): void | ||
end(value?: any): void | ||
export class EncoderStream extends Transform { | ||
constructor(options?: Options | { highWaterMark: number, emitClose: boolean, allowHalfOpen: boolean }) | ||
} |
export { Encoder, addExtension, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './encode.js' | ||
export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS, clearSource } from './decode.js' | ||
export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './decode.js' | ||
export { decodeIter, encodeIter } from './iterators.js' | ||
export const useRecords = false | ||
export const mapsAsObjects = true |
@@ -1,3 +0,3 @@ | ||
export { Encoder, addExtension, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } from './encode.js' | ||
export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS } from './decode.js' | ||
export { Encoder, addExtension, encode, NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT, REUSE_BUFFER_MODE } from './encode.js' | ||
export { Tag, Decoder, decodeMultiple, decode, FLOAT32_OPTIONS, clearSource, roundFloat32 } from './decode.js' | ||
export { EncoderStream, DecoderStream } from './stream.js' | ||
@@ -4,0 +4,0 @@ export { decodeIter, encodeIter } from './iterators.js' |
{ | ||
"name": "cbor-x", | ||
"author": "Kris Zyp", | ||
"version": "0.8.3", | ||
"version": "0.9.0", | ||
"description": "Ultra-fast CBOR implementation with tag extensions for records and structured cloning", | ||
"license": "MIT", | ||
"types": "./index.d.ts", | ||
"main": "./dist/node.cjs", | ||
"module": "./index.js", | ||
"keywords": [ | ||
@@ -19,4 +21,5 @@ "CBOR", | ||
"scripts": { | ||
"benchmark": "node ./tests/benchmark.js", | ||
"benchmark": "node ./tests/benchmark.cjs", | ||
"build": "rollup -c", | ||
"dry-run": "npm publish --dry-run", | ||
"prepare": "npm run build", | ||
@@ -26,3 +29,2 @@ "test": "mocha tests/test**.*js -u tdd --experimental-json-modules" | ||
"type": "module", | ||
"main": "./dist/node.cjs", | ||
"exports": { | ||
@@ -34,7 +36,5 @@ ".": { | ||
}, | ||
"default": { | ||
"import": "./index.js" | ||
} | ||
"default": "./index.js" | ||
}, | ||
"./pack": { | ||
"./encode": { | ||
"node": { | ||
@@ -45,6 +45,6 @@ "import": "./index.js", | ||
"default": { | ||
"import": "./pack.js" | ||
"import": "./encode.js" | ||
} | ||
}, | ||
"./unpack": { | ||
"./decode": { | ||
"node": { | ||
@@ -55,3 +55,3 @@ "import": "./index.js", | ||
"default": { | ||
"import": "./unpack.js" | ||
"import": "./decode.js" | ||
} | ||
@@ -61,3 +61,3 @@ } | ||
"optionalDependencies": { | ||
"cbor-extract": "^0.3.1" | ||
"cbor-extract": "^0.3.2" | ||
}, | ||
@@ -64,0 +64,0 @@ "devDependencies": { |
@@ -99,2 +99,4 @@ # cbor-x | ||
Streaming with record structures works by encoding a structure the first time it is seen in a stream and referencing the structure in later messages that are sent across that stream. When an encoder can expect a decoder to understand previous structure references, this can be configured using the `sequential: true` flag, which is auto-enabled by streams, but can also be used with Packr instances. | ||
### Shared Record Structures | ||
@@ -123,3 +125,3 @@ Another useful way of using cbor-x, and the record extension, is for storing data in a databases, files, or other storage systems. If a number of objects with common data structures are being stored, a shared structure can be used to greatly improve data storage and deserialization efficiency. In the simplest form, provide a `structures` array, which is updated if any new object structure is encountered: | ||
``` | ||
Cbor-x will automatically add and saves structures as it encounters any new object structures (up to a limit of 32). It will always add structures in incremental/compatible way: Any object encoded with an earlier structure can be decoded with a later version (as long as it is persisted). | ||
Cbor-x will automatically add and saves structures as it encounters any new object structures (up to a limit of 64). It will always add structures in incremental/compatible way: Any object encoded with an earlier structure can be decoded with a later version (as long as it is persisted). | ||
@@ -152,2 +154,3 @@ ### Reading Multiple Values | ||
* `useTimestamp32` - Encode JS `Date`s in 32-bit format when possible by dropping the milliseconds. This is a more efficient encoding of dates. You can also cause dates to use 32-bit format by manually setting the milliseconds to zero (`date.setMilliseconds(0)`). | ||
* `sequential` - Encode structures in serialized data, and reference previously encoded structures with expectation that decoder will read the encoded structures in the same order as encoded, with `unpackMultiple`. | ||
* `largeBigIntToFloat` - If a bigint needs to be encoded that is larger than will fit in 64-bit integers, it will be encoded as a float-64 (otherwise will throw a RangeError). | ||
@@ -164,6 +167,8 @@ * `useTag259ForMaps` - This flag indicates if [tag 259 (explicit maps)](https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) should be used to encode JS `Map`s. When using records is enabled, this is disabled by default, since plain objects are encoded with record structures and unambigiously differentiated from `Map`s, which are encoded as CBOR maps. Without using records, this enabled by default and is necessary to distinguish plain objects from `Map`s (but can be disabled by setting this to `false`). | ||
* `DECIMAL_ROUND` (3) - Always will encode non-integers as 32-bit float, and when decoding 32-bit float, round to the significant decimal digits (usually 7, but 6 or 8 digits for some ranges). | ||
* `DECIMAL_FIT` (4) - Only encode non-integers as 32-bit float if all significant digits (usually up to 7) can be unamiguously encoded as a 32-bit float, and decode with decimal rounding (same as above). This will ensure round-trip encoding/decoding without loss in precision and use 32-bit when possible. | ||
* `DECIMAL_FIT` (4) - Only encode non-integers as 32-bit float if all significant digits (usually up to 7) can be unamiguously encoded as a 32-bit float, and decode with decimal rounding (same as above). This will ensure round-trip encoding/decoding without loss in precision and uses 32-bit when possible. | ||
Note, that the performance is decreased with decimal rounding by about 20-25%, although if only 5% of your values are floating point, that will only have about a 1% impact overall. | ||
In addition, msgpackr exports a `roundFloat32(number)` function that can be used to round floating point numbers to the maximum significant decimal digits that can be stored in 32-bit float, just as DECIMAL_ROUND does when decoding. This can be useful for determining how a number will be decoded prior to encoding it. | ||
## Performance | ||
@@ -251,3 +256,3 @@ Cbor-x is fast. Really fast. Here is comparison with the next fastest JS projects using the benchmark tool from `msgpack-lite` (and the sample data is from some clinical research data we use that has a good mix of different value types and structures). It also includes comparison to V8 native JSON functionality, and JavaScript Avro (`avsc`, a very optimized Avro implementation): | ||
### Dates | ||
cbor-x saves all JavaScript `Date`s using the standard CBOR date extension (tag 1). | ||
Cbor-x saves all JavaScript `Date`s using the standard CBOR date extension (tag 1). | ||
@@ -257,5 +262,29 @@ ### Structured Cloning | ||
### List of supported tags for decoding | ||
Here is a list of CBOR tags that are supported for decoding: | ||
* 0 - String date | ||
* 1 - Numeric Date | ||
* 2 - BigInt | ||
* 3 - Negative BigInt | ||
* 27 - Generic named objects (used for Error, RegExp) | ||
* 64 - Uint8Array | ||
* 68 - Uint8ClampedArray | ||
* 69 - Uint16Array | ||
* 70 - Uint32Array | ||
* 71 - BigUint64Array | ||
* 72 - Int8Array | ||
* 77 - Int16Array | ||
* 78 - Int32Array | ||
* 79 - BigInt64Array | ||
* 81 - Float32Array | ||
* 82 - Float64Array | ||
* 105 - Records | ||
* 258 - Set | ||
* 259 - Map | ||
* 40009, 40010 - Pointers for cycles | ||
## Alternate Encoding/Package | ||
The high-performance serialization and deserialization algorithms in this package are also available in the [msgpackr](https://github.com/kriszyp/msgpackr) for the MessagePack format, with the same API and design. A quick summary of the pros and cons of using MessagePack vs CBOR are: | ||
* MessagePack has wider adoption, and, at least with this implementation is slightly more efficient (by roughly 2-4%, but YMMV). | ||
* MessagePack has wider adoption, and, at least with this implementation is slightly more efficient (by roughly 1%, but YMMV). | ||
* CBOR has an [official IETF standardization track](https://www.rfc-editor.org/rfc/rfc8949.html), and the record extensions is conceptually/philosophically a better fit for CBOR tags. | ||
@@ -268,3 +297,3 @@ | ||
### Browser Consideration | ||
CBOR can be a great choice for high-performance data delivery to browsers, as reasonable data size is possible without compression. And CBOR works very well in modern browsers. However, it is worth noting that if you want highly compact data, brotli or gzip are most effective in compressing, and CBOR's character frequency tends to defeat Huffman encoding used by these standard compression algorithms, resulting in less compact data than compressed JSON. | ||
CBOR can be a great choice for high-performance data delivery to browsers, as reasonable data size is possible without compression. And CBOR works very well in modern browsers. However, it is worth noting that if you want highly compact data, brotli or gzip are most effective in compressing, and CBOR's character frequency tends to defeat Huffman encoding used by these standard compression algorithms, often resulting in less compact data than compressed JSON. | ||
@@ -271,0 +300,0 @@ ### Credits |
@@ -10,15 +10,11 @@ import { Transform } from 'stream' | ||
options = {} | ||
options.writableObjectMode = true | ||
super(options) | ||
options.sequential = true | ||
this.encoder = new Encoder(options) | ||
this.encoder = options.encoder || new Encoder(options) | ||
} | ||
write(value) { | ||
_transform(value, encoding, callback) { | ||
this.push(this.encoder.encode(value)) | ||
callback() | ||
} | ||
end(value) { | ||
if (value != null) | ||
this.push(this.encoder.encode(value)) | ||
this.push(null) | ||
} | ||
} | ||
@@ -33,3 +29,3 @@ | ||
options.structures = [] | ||
this.decoder = new Decoder(options) | ||
this.decoder = options.decoder || new Decoder(options) | ||
} | ||
@@ -36,0 +32,0 @@ _transform(chunk, encoding, callback) { |
import { EncoderStream, DecoderStream } from '../node-index.js' | ||
import stream from 'stream' | ||
import chai from 'chai' | ||
import util from 'util' | ||
import fs from 'fs' | ||
const finished = util.promisify(stream.finished) | ||
var assert = chai.assert | ||
@@ -50,2 +53,9 @@ | ||
})) | ||
teardown(function() { | ||
try { | ||
fs.unlinkSync('test-output.msgpack') | ||
}catch(error){} | ||
}) | ||
}) | ||
@@ -87,2 +87,9 @@ import * as CBOR from '../index.js' | ||
test('255 chars', function() { | ||
const data = 'RRZG9A6I7xupPeOZhxcOcioFsuhszGOdyDUcbRf4Zef2kdPIfC9RaLO4jTM5JhuZvTsF09fbRHMGtqk7YAgu3vespeTe9l61ziZ6VrMnYu2CamK96wCkmz0VUXyqaiUoTPgzk414LS9yYrd5uh7w18ksJF5SlC2e91rukWvNqAZJjYN3jpkqHNOFchCwFrhbxq2Lrv1kSJPYCx9blRg2hGmYqTbElLTZHv20iNqwZeQbRMgSBPT6vnbCBPnOh1W' | ||
var serialized = CBOR.encode(data) | ||
var deserialized = CBOR.decode(serialized) | ||
assert.equal(deserialized, data) | ||
}) | ||
test('encode/decode sample data', function(){ | ||
@@ -89,0 +96,0 @@ var data = sampleData |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
398830
39
7826
296
9