msgpackr 1.5.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +10 -2
- package/dist/index.min.js +6 -7
- package/dist/node.cjs +10 -2
- package/dist/str.cjs +100 -0
- package/dist/test.js +2 -0
- package/pack.js +9 -1
- package/package.json +1 -1
- package/tests/test.js +2 -0
- package/unpack.js +1 -1
package/README.md
CHANGED
|
@@ -168,6 +168,7 @@ The following options properties can be provided to the Packr or Unpackr constru
|
|
|
168
168
|
* `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).
|
|
169
169
|
* `encodeUndefinedAsNil` - Encodes a value of `undefined` as a MessagePack `nil`, the same as a `null`.
|
|
170
170
|
* `int64AsNumber` - This will decode uint64 and int64 numbers as standard JS numbers rather than as bigint numbers.
|
|
171
|
+
* `onInvalidDate` - This can be provided as function that will be called when an invalid date is provided. The function can throw an error, or return a value that will be encoded in place of the invalid date. If not provided, an invalid date will be encoded as an invalid timestamp (which decodes with msgpackr back to an invalid date).
|
|
171
172
|
|
|
172
173
|
### 32-bit Float Options
|
|
173
174
|
By default all non-integer numbers are serialized as 64-bit float (double). This is fast, and ensures maximum precision. However, often real-world data doesn't not need 64-bits of precision, and using 32-bit encoding can be much more space efficient. There are several options that provide more efficient encodings. Using the decimal rounding options for encoding and decoding provides lossless storage of common decimal representations like 7.99, in more efficient 32-bit format (rather than 64-bit). The `useFloat32` property has several possible options, available from the module as constants:
|
package/dist/index.js
CHANGED
|
@@ -870,7 +870,7 @@
|
|
|
870
870
|
((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
|
|
871
871
|
(((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
|
|
872
872
|
else
|
|
873
|
-
|
|
873
|
+
return new Date('invalid')
|
|
874
874
|
}; // notepack defines extension 0 to mean undefined, so use that as the default here
|
|
875
875
|
// registration of bulk record definition?
|
|
876
876
|
// currentExtensions[0x52] = () =>
|
|
@@ -1555,7 +1555,7 @@
|
|
|
1555
1555
|
|
|
1556
1556
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
|
|
1557
1557
|
extensions = [{
|
|
1558
|
-
pack(date, allocateForWrite) {
|
|
1558
|
+
pack(date, allocateForWrite, pack) {
|
|
1559
1559
|
let seconds = date.getTime() / 1000;
|
|
1560
1560
|
if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
|
|
1561
1561
|
// Timestamp 32
|
|
@@ -1570,6 +1570,14 @@
|
|
|
1570
1570
|
target[position++] = 0xff;
|
|
1571
1571
|
targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0));
|
|
1572
1572
|
targetView.setUint32(position + 4, seconds);
|
|
1573
|
+
} else if (isNaN(seconds)) {
|
|
1574
|
+
if (this.onInvalidDate)
|
|
1575
|
+
return pack(this.onInvalidDate())
|
|
1576
|
+
// Intentionally invalid timestamp
|
|
1577
|
+
let { target, targetView, position} = allocateForWrite(3);
|
|
1578
|
+
target[position++] = 0xd4;
|
|
1579
|
+
target[position++] = 0xff;
|
|
1580
|
+
target[position++] = 0xff;
|
|
1573
1581
|
} else {
|
|
1574
1582
|
// Timestamp 96
|
|
1575
1583
|
let { target, targetView, position} = allocateForWrite(15);
|
package/dist/index.min.js
CHANGED
|
@@ -44,9 +44,7 @@ E.set(a,d);let f=e();// read the next value as the target object to id
|
|
|
44
44
|
return d.used?Object.assign(b,f):(d.target=f,f);// no cycle, can just use the returned read object
|
|
45
45
|
},K[112]=()=>{// pointer extension (for structured clones)
|
|
46
46
|
let a=F.getUint32(G-4),b=E.get(a);return b.used=!0,b.target},K[115]=()=>new Set(e());const $=["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64","BigInt64","BigUint64"].map(a=>a+"Array");K[116]=a=>{let b=a[0],c=$[b];if(!c)throw new Error("Could not find typed array for code "+b);// we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
|
|
47
|
-
return new Z[c](Uint8Array.prototype.slice.call(a,1).buffer)},K[120]=()=>{let a=e();return new RegExp(a[0],a[1])},K[255]=a=>
|
|
48
|
-
if(4==a.length)return new Date(1e3*(16777216*a[0]+(a[1]<<16)+(a[2]<<8)+a[3]));if(8==a.length)return new Date(((a[0]<<22)+(a[1]<<14)+(a[2]<<6)+(a[3]>>2))/1e6+1e3*(4294967296*(3&a[3])+16777216*a[4]+(a[5]<<16)+(a[6]<<8)+a[7]));if(12==a.length)// TODO: Implement support for negative
|
|
49
|
-
return new Date(((a[0]<<24)+(a[1]<<16)+(a[2]<<8)+a[3])/1e6+1e3*((128&a[4]?-281474976710656:0)+1099511627776*a[6]+4294967296*a[7]+16777216*a[8]+(a[9]<<16)+(a[10]<<8)+a[11]));throw new Error("Invalid timestamp length")};const _=Array(147);// this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
47
|
+
return new Z[c](Uint8Array.prototype.slice.call(a,1).buffer)},K[120]=()=>{let a=e();return new RegExp(a[0],a[1])},K[255]=a=>4==a.length?new Date(1e3*(16777216*a[0]+(a[1]<<16)+(a[2]<<8)+a[3])):8==a.length?new Date(((a[0]<<22)+(a[1]<<14)+(a[2]<<6)+(a[3]>>2))/1e6+1e3*(4294967296*(3&a[3])+16777216*a[4]+(a[5]<<16)+(a[6]<<8)+a[7])):12==a.length?new Date(((a[0]<<24)+(a[1]<<16)+(a[2]<<8)+a[3])/1e6+1e3*((128&a[4]?-281474976710656:0)+1099511627776*a[6]+4294967296*a[7]+16777216*a[8]+(a[9]<<16)+(a[10]<<8)+a[11])):new Date("invalid");const _=Array(147);// this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
50
48
|
for(let c=0;256>c;c++)_[c]=+("1e"+b(45.15-.30103*c));var aa=new P({useRecords:!1});const ba=aa.unpack,ca=aa.unpackMultiple,da=aa.unpack,ea={NEVER:0,ALWAYS:1,DECIMAL_ROUND:3,DECIMAL_FIT:4};let fa,ga=new Float32Array(1),ha=new Uint8Array(ga.buffer,0,4);try{fa=new TextEncoder}catch(a){}let ia,ja;const ka="undefined"!=typeof Buffer,la=ka?Buffer.allocUnsafeSlow:Uint8Array,ma=ka?Buffer:Uint8Array,na=ka?4294967296:2144337920;let oa,pa,qa,ra=0;const sa=Symbol("record-id");class ta extends P{constructor(a){super(a),this.offset=0;let b,c,d,e,f,g=0,h=ma.prototype.utf8Write?function(a,b,c){return oa.utf8Write(a,b,c)}:!!(fa&&fa.encodeInto)&&function(a,b){return fa.encodeInto(a,oa.subarray(b)).written},i=this;a||(a={});let j=a&&a.sequential,k=a.structures||a.saveStructures,l=a.maxSharedStructures;if(null==l&&(l=k?32:0),8160<l)throw new Error("Maximum maxSharedStructure is 8160");let m=a.maxOwnStructures;null==m&&(m=k?32:64),j&&!a.saveStructures&&(this.structures=[]);// two byte record ids for shared structures
|
|
51
49
|
let n=32<l||64<m+l,o=l+64,p=l+m+64;if(8256<p)throw new Error("Maximum maxSharedStructure + maxOwnStructure is 8192");let q=[],r=0,s=0;this.pack=this.encode=function(a,h){if(oa||(oa=new la(8192),pa=new DataView(oa.buffer,0,8192),ra=0),qa=oa.length-10,2048>qa-ra?(oa=new la(oa.length),pa=new DataView(oa.buffer,0,oa.length),qa=oa.length-10,ra=0):ra=2147483640&ra+7,b=ra,f=i.structuredClone?new Map:null,c=i.structures,c){c.uninitialized&&(c=i._mergeStructures(i.getStructures()));let a=c.sharedLength||0;if(a>l)//if (maxSharedStructures <= 32 && sharedStructures.sharedLength > 32) // TODO: could support this, but would need to update the limit ids
|
|
52
50
|
throw new Error("Shared structures is larger than maximum shared structures, try increasing maxSharedStructures to "+c.sharedLength);if(!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[sa]=d+64}g=a}j||(c.nextId=a+64)}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
|
|
@@ -102,10 +100,11 @@ h=o),e.nextId=h+1);let a=c.highByte=96<=h&&n?h-96>>5:-1;f[sa]=h,e[h-64]=c,h<o?(c
|
|
|
102
100
|
for(let b=0,d=c.length;b<d;b++)t(a[c[b]])},x=a=>{var c=Math.min,d=Math.round,e=Math.max;let f;if(16777216<a){// special handling for really large buffers
|
|
103
101
|
if(a-b>na)throw new Error("Packed buffer would be larger than maximum buffer size");f=c(na,4096*d(e((a-b)*(67108864<a?1.25:2),4194304)/4096))}else// faster handling for smaller buffers
|
|
104
102
|
f=(e(a-b<<2,oa.length-1)>>12)+1<<12;let g=new la(f);return pa=new DataView(g.buffer,0,f),oa.copy?oa.copy(g,0,b,a):g.set(oa.slice(b,a)),ra-=b,b=0,qa=g.length-10,oa=g}}useBuffer(a){// this means we are finished using our own buffer and we can write over it safely
|
|
105
|
-
oa=a,pa=new DataView(oa.buffer,oa.byteOffset,oa.byteLength),ra=0}}ja=[Date,Set,Error,RegExp,ArrayBuffer,Object.getPrototypeOf(Uint8Array.prototype).constructor/*TypedArray*/,M],ia=[{pack(a,c){let
|
|
106
|
-
let{target:a,targetView:b,position:
|
|
107
|
-
let{target:b,targetView:
|
|
108
|
-
let{target:
|
|
103
|
+
oa=a,pa=new DataView(oa.buffer,oa.byteOffset,oa.byteLength),ra=0}}ja=[Date,Set,Error,RegExp,ArrayBuffer,Object.getPrototypeOf(Uint8Array.prototype).constructor/*TypedArray*/,M],ia=[{pack(a,c,d){let e=a.getTime()/1e3;if((this.useTimestamp32||0===a.getMilliseconds())&&0<=e&&4294967296>e){// Timestamp 32
|
|
104
|
+
let{target:a,targetView:b,position:d}=c(6);a[d++]=214,a[d++]=255,b.setUint32(d,e)}else if(0<e&&17179869184>e){// Timestamp 64
|
|
105
|
+
let{target:b,targetView:d,position:f}=c(10);b[f++]=215,b[f++]=255,d.setUint32(f,4e6*a.getMilliseconds()+(e/1e3/4294967296>>0)),d.setUint32(f+4,e)}else if(isNaN(e)){if(this.onInvalidDate)return d(this.onInvalidDate());// Intentionally invalid timestamp
|
|
106
|
+
let{target:a,targetView:b,position:e}=c(3);a[e++]=212,a[e++]=255,a[e++]=255}else{// Timestamp 96
|
|
107
|
+
let{target:d,targetView:f,position:g}=c(15);d[g++]=199,d[g++]=12,d[g++]=255,f.setUint32(g,1e6*a.getMilliseconds()),f.setBigInt64(g+4,BigInt(b(e)))}}},{pack(a,b,c){let d=Array.from(a),{target:e,position:f}=b(this.structuredClone?3:0);this.structuredClone&&(e[f++]=212,e[f++]=115,e[f++]=0),c(d)}},{pack(a,b,c){let{target:d,position:e}=b(this.structuredClone?3:0);this.structuredClone&&(d[e++]=212,d[e++]=101,d[e++]=0),c([a.name,a.message])}},{pack(a,b,c){let{target:d,position:e}=b(this.structuredClone?3:0);this.structuredClone&&(d[e++]=212,d[e++]=120,d[e++]=0),c([a.source,a.flags])}},{pack(a,b){this.structuredClone?s(a,16,b):t(ka?Buffer.from(a):new Uint8Array(a),b)}},{pack(a,b){let c=a.constructor;c!==ma&&this.structuredClone?s(a,$.indexOf(c.name),b):t(a,b)}},{pack(a,b){// specific 0xC1 object
|
|
109
108
|
let{target:c,position:d}=b(1);c[d]=193}}];let ua=new ta({useRecords:!1});const va=ua.pack,wa=ua.pack,{NEVER:xa,ALWAYS:ya,DECIMAL_ROUND:za,DECIMAL_FIT:Aa}=ea,Ba=1e3;a.ALWAYS=ya,a.C1=N,a.DECIMAL_FIT=Aa,a.DECIMAL_ROUND=za,a.Decoder=P,a.Encoder=ta,a.FLOAT32_OPTIONS=ea,a.NEVER=xa,a.Packr=ta,a.REUSE_BUFFER_MODE=Ba,a.Unpackr=P,a.addExtension=w,a.clearSource=q,a.decode=da,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 P(b);let d;const e=a=>{let b;// if there's incomplete data from previous chunk, concatinate and try again
|
|
110
109
|
d&&(a=Buffer.concat([d,a]),d=void 0);try{b=c.unpackMultiple(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.encode=wa,a.encodeIter=/**
|
|
111
110
|
* Given an Iterable first argument, returns an Iterable where each value is packed as a Buffer
|
package/dist/node.cjs
CHANGED
|
@@ -913,7 +913,7 @@ currentExtensions[0xff] = (data) => {
|
|
|
913
913
|
((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
|
|
914
914
|
(((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
|
|
915
915
|
else
|
|
916
|
-
|
|
916
|
+
return new Date('invalid')
|
|
917
917
|
}; // notepack defines extension 0 to mean undefined, so use that as the default here
|
|
918
918
|
// registration of bulk record definition?
|
|
919
919
|
// currentExtensions[0x52] = () =>
|
|
@@ -1602,7 +1602,7 @@ class Packr extends Unpackr {
|
|
|
1602
1602
|
|
|
1603
1603
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ];
|
|
1604
1604
|
extensions = [{
|
|
1605
|
-
pack(date, allocateForWrite) {
|
|
1605
|
+
pack(date, allocateForWrite, pack) {
|
|
1606
1606
|
let seconds = date.getTime() / 1000;
|
|
1607
1607
|
if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
|
|
1608
1608
|
// Timestamp 32
|
|
@@ -1617,6 +1617,14 @@ extensions = [{
|
|
|
1617
1617
|
target[position++] = 0xff;
|
|
1618
1618
|
targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0));
|
|
1619
1619
|
targetView.setUint32(position + 4, seconds);
|
|
1620
|
+
} else if (isNaN(seconds)) {
|
|
1621
|
+
if (this.onInvalidDate)
|
|
1622
|
+
return pack(this.onInvalidDate())
|
|
1623
|
+
// Intentionally invalid timestamp
|
|
1624
|
+
let { target, targetView, position} = allocateForWrite(3);
|
|
1625
|
+
target[position++] = 0xd4;
|
|
1626
|
+
target[position++] = 0xff;
|
|
1627
|
+
target[position++] = 0xff;
|
|
1620
1628
|
} else {
|
|
1621
1629
|
// Timestamp 96
|
|
1622
1630
|
let { target, targetView, position} = allocateForWrite(15);
|
package/dist/str.cjs
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
let utfz = require('../../msgpack-benchmark/node_modules/utfz-lib')
|
|
2
|
+
|
|
3
|
+
var safeEnd = 1000000;
|
|
4
|
+
var b = new Uint8Array(32768)
|
|
5
|
+
function writeString(value, target, position) {
|
|
6
|
+
var length, strLength = value.length;
|
|
7
|
+
let headerSize;
|
|
8
|
+
// first we estimate the header size, so we can write to the correct location
|
|
9
|
+
if (strLength < 0x20) {
|
|
10
|
+
headerSize = 1;
|
|
11
|
+
} else if (strLength < 0x100) {
|
|
12
|
+
headerSize = 2;
|
|
13
|
+
} else if (strLength < 0x10000) {
|
|
14
|
+
headerSize = 3;
|
|
15
|
+
} else {
|
|
16
|
+
headerSize = 5;
|
|
17
|
+
}
|
|
18
|
+
let maxBytes = strLength * 3;
|
|
19
|
+
//if (position + maxBytes > safeEnd)
|
|
20
|
+
// target = makeRoom(position + maxBytes);
|
|
21
|
+
for (let i = 0; i < 100; i++) {
|
|
22
|
+
length = pack(value, strLength, target, position + headerSize);
|
|
23
|
+
}
|
|
24
|
+
if (strLength < 0x40 || !encodeUtf8) {
|
|
25
|
+
var strPosition = position + headerSize;
|
|
26
|
+
var c2 = 0;
|
|
27
|
+
for (let i = 0; i < strLength; i++) {
|
|
28
|
+
const c1 = value.charCodeAt(i);
|
|
29
|
+
if (c1 < 0x80) {
|
|
30
|
+
target[strPosition++] = c1;
|
|
31
|
+
} else if (c1 < 0x800) {
|
|
32
|
+
target[strPosition++] = c1 >> 6 | 0xc0;
|
|
33
|
+
target[strPosition++] = c1 & 0x3f | 0x80;
|
|
34
|
+
} else if (
|
|
35
|
+
(c1 & 0xfc00) === 0xd800 &&
|
|
36
|
+
((c2 = value.charCodeAt(i + 1)) & 0xfc00) === 0xdc00
|
|
37
|
+
) {
|
|
38
|
+
c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff);
|
|
39
|
+
i++;
|
|
40
|
+
target[strPosition++] = c1 >> 18 | 0xf0;
|
|
41
|
+
target[strPosition++] = c1 >> 12 & 0x3f | 0x80;
|
|
42
|
+
target[strPosition++] = c1 >> 6 & 0x3f | 0x80;
|
|
43
|
+
target[strPosition++] = c1 & 0x3f | 0x80;
|
|
44
|
+
} else {
|
|
45
|
+
target[strPosition++] = c1 >> 12 | 0xe0;
|
|
46
|
+
target[strPosition++] = c1 >> 6 & 0x3f | 0x80;
|
|
47
|
+
target[strPosition++] = c1 & 0x3f | 0x80;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
length = strPosition - position - headerSize;
|
|
51
|
+
} else {
|
|
52
|
+
length = encodeUtf8(value, position + headerSize, maxBytes);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
if (length < 0x20) {
|
|
57
|
+
target[position++] = 0xa0 | length;
|
|
58
|
+
} else if (length < 0x100) {
|
|
59
|
+
if (headerSize < 2) {
|
|
60
|
+
target.copyWithin(position + 2, position + 1, position + 1 + length);
|
|
61
|
+
}
|
|
62
|
+
target[position++] = 0xd9;
|
|
63
|
+
target[position++] = length;
|
|
64
|
+
} else if (length < 0x10000) {
|
|
65
|
+
if (headerSize < 3) {
|
|
66
|
+
target.copyWithin(position + 3, position + 2, position + 2 + length);
|
|
67
|
+
}
|
|
68
|
+
target[position++] = 0xda;
|
|
69
|
+
target[position++] = length >> 8;
|
|
70
|
+
target[position++] = length & 0xff;
|
|
71
|
+
} else {
|
|
72
|
+
if (headerSize < 5) {
|
|
73
|
+
target.copyWithin(position + 5, position + 3, position + 3 + length);
|
|
74
|
+
}
|
|
75
|
+
target[position++] = 0xdb;
|
|
76
|
+
targetView.setUint32(position, length);
|
|
77
|
+
position += 4;
|
|
78
|
+
}
|
|
79
|
+
return position + length
|
|
80
|
+
};
|
|
81
|
+
const pack = (str, length, buf, offset) => {
|
|
82
|
+
const start = offset;
|
|
83
|
+
let currHigh = 0;
|
|
84
|
+
for (let i = 0; i < length; i++) {
|
|
85
|
+
const code = str.charCodeAt(i);
|
|
86
|
+
const high = code >> 8;
|
|
87
|
+
if (high !== currHigh) {
|
|
88
|
+
buf[i + offset++] = 0;
|
|
89
|
+
buf[i + offset++] = high;
|
|
90
|
+
currHigh = high;
|
|
91
|
+
}
|
|
92
|
+
const low = code & 0xff;
|
|
93
|
+
buf[i + offset] = low;
|
|
94
|
+
if (!low) {
|
|
95
|
+
buf[i + ++offset] = currHigh;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return length + offset - start;
|
|
99
|
+
};
|
|
100
|
+
module.exports = writeString;
|
package/dist/test.js
CHANGED
|
@@ -989,6 +989,7 @@
|
|
|
989
989
|
date: new Date(1532219539733),
|
|
990
990
|
farFutureDate: new Date(3532219539133),
|
|
991
991
|
ancient: new Date(-3532219539133),
|
|
992
|
+
invalidDate: new Date('invalid')
|
|
992
993
|
};
|
|
993
994
|
let packr = new Packr();
|
|
994
995
|
var serialized = packr.pack(data);
|
|
@@ -998,6 +999,7 @@
|
|
|
998
999
|
assert.equal(deserialized.date.getTime(), 1532219539733);
|
|
999
1000
|
assert.equal(deserialized.farFutureDate.getTime(), 3532219539133);
|
|
1000
1001
|
assert.equal(deserialized.ancient.getTime(), -3532219539133);
|
|
1002
|
+
assert.equal(deserialized.invalidDate.toString(), 'Invalid Date');
|
|
1001
1003
|
});
|
|
1002
1004
|
test('map/date with options', function(){
|
|
1003
1005
|
var map = new Map();
|
package/pack.js
CHANGED
|
@@ -622,7 +622,7 @@ function copyBinary(source, target, targetOffset, offset, endOffset) {
|
|
|
622
622
|
|
|
623
623
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/, C1Type ]
|
|
624
624
|
extensions = [{
|
|
625
|
-
pack(date, allocateForWrite) {
|
|
625
|
+
pack(date, allocateForWrite, pack) {
|
|
626
626
|
let seconds = date.getTime() / 1000
|
|
627
627
|
if ((this.useTimestamp32 || date.getMilliseconds() === 0) && seconds >= 0 && seconds < 0x100000000) {
|
|
628
628
|
// Timestamp 32
|
|
@@ -637,6 +637,14 @@ extensions = [{
|
|
|
637
637
|
target[position++] = 0xff
|
|
638
638
|
targetView.setUint32(position, date.getMilliseconds() * 4000000 + ((seconds / 1000 / 0x100000000) >> 0))
|
|
639
639
|
targetView.setUint32(position + 4, seconds)
|
|
640
|
+
} else if (isNaN(seconds)) {
|
|
641
|
+
if (this.onInvalidDate)
|
|
642
|
+
return pack(this.onInvalidDate())
|
|
643
|
+
// Intentionally invalid timestamp
|
|
644
|
+
let { target, targetView, position} = allocateForWrite(3)
|
|
645
|
+
target[position++] = 0xd4
|
|
646
|
+
target[position++] = 0xff
|
|
647
|
+
target[position++] = 0xff
|
|
640
648
|
} else {
|
|
641
649
|
// Timestamp 96
|
|
642
650
|
let { target, targetView, position} = allocateForWrite(15)
|
package/package.json
CHANGED
package/tests/test.js
CHANGED
|
@@ -416,6 +416,7 @@ suite('msgpackr basic tests', function(){
|
|
|
416
416
|
date: new Date(1532219539733),
|
|
417
417
|
farFutureDate: new Date(3532219539133),
|
|
418
418
|
ancient: new Date(-3532219539133),
|
|
419
|
+
invalidDate: new Date('invalid')
|
|
419
420
|
}
|
|
420
421
|
let packr = new Packr()
|
|
421
422
|
var serialized = packr.pack(data)
|
|
@@ -425,6 +426,7 @@ suite('msgpackr basic tests', function(){
|
|
|
425
426
|
assert.equal(deserialized.date.getTime(), 1532219539733)
|
|
426
427
|
assert.equal(deserialized.farFutureDate.getTime(), 3532219539133)
|
|
427
428
|
assert.equal(deserialized.ancient.getTime(), -3532219539133)
|
|
429
|
+
assert.equal(deserialized.invalidDate.toString(), 'Invalid Date')
|
|
428
430
|
})
|
|
429
431
|
test('map/date with options', function(){
|
|
430
432
|
var map = new Map()
|
package/unpack.js
CHANGED
|
@@ -911,7 +911,7 @@ currentExtensions[0xff] = (data) => {
|
|
|
911
911
|
((data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]) / 1000000 +
|
|
912
912
|
(((data[4] & 0x80) ? -0x1000000000000 : 0) + data[6] * 0x10000000000 + data[7] * 0x100000000 + data[8] * 0x1000000 + (data[9] << 16) + (data[10] << 8) + data[11]) * 1000)
|
|
913
913
|
else
|
|
914
|
-
|
|
914
|
+
return new Date('invalid')
|
|
915
915
|
} // notepack defines extension 0 to mean undefined, so use that as the default here
|
|
916
916
|
// registration of bulk record definition?
|
|
917
917
|
// currentExtensions[0x52] = () =>
|