You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.3 KiB
JavaScript
96 lines
2.3 KiB
JavaScript
"use strict";
|
|
|
|
const assert = require("assert");
|
|
|
|
const bigintBuffer = require("../bigint-buffer");
|
|
const createArithmeticCoder = require("./bitmask-arithmetic");
|
|
|
|
module.exports = function createDurationEncoder() {
|
|
// 55 bits for value + 1 bit for sign = 56 bits = 7 bytes
|
|
// NOTE: Maximums are exclusive!
|
|
|
|
let coder = createArithmeticCoder([
|
|
{ name: "milliseconds", minimum: 0, maximum: 1000 },
|
|
{ name: "seconds", minimum: 0, maximum: 64 }, // No, this is not a typo; leap seconds are a thing
|
|
{ name: "minutes", minimum: 0, maximum: 60 },
|
|
{ name: "hours", minimum: 0, maximum: 25 },
|
|
{ name: "days", minimum: 0, maximum: 31 },
|
|
{ name: "months", minimum: 0, maximum: 12 },
|
|
{ name: "years", minimum: 0, maximum: 8000 },
|
|
]);
|
|
|
|
let zeroPoint = 2n ** coder.bits; // first bit is a 1
|
|
|
|
return {
|
|
bits: coder.bits + 1n,
|
|
encode: function (value) {
|
|
let { negative, ... rest } = value;
|
|
let number = coder.encode(rest);
|
|
|
|
// NOTE: This approach ensures that values are correctly sorted even in their buffer representation!
|
|
let signedNumber = (negative)
|
|
? zeroPoint - number
|
|
: zeroPoint + number;
|
|
|
|
return {
|
|
value: bigintBuffer.toBuffer(signedNumber),
|
|
auxiliaryBlob: undefined
|
|
};
|
|
},
|
|
decode: function (bytes) {
|
|
let signedNumber = bigintBuffer.toBigint(bytes);
|
|
let negative = (signedNumber < zeroPoint);
|
|
|
|
let number = (negative)
|
|
? zeroPoint - signedNumber
|
|
: signedNumber - zeroPoint;
|
|
|
|
// FIXME: Update to new decode API
|
|
let decoded = coder.decode(number);
|
|
|
|
return {
|
|
... decoded,
|
|
negative: negative
|
|
};
|
|
}
|
|
};
|
|
};
|
|
|
|
// let coder = module.exports();
|
|
|
|
// let data1 = {
|
|
// negative: true,
|
|
// seconds: 1n
|
|
// };
|
|
|
|
// let data2 = {
|
|
// negative: false,
|
|
// seconds: 1n
|
|
// };
|
|
|
|
// let encoded1 = coder.encode(data1);
|
|
// let encoded2 = coder.encode(data2);
|
|
|
|
// console.log({ encoded1, encoded2 });
|
|
|
|
// let decoded1 = coder.decode(encoded1);
|
|
// let decoded2 = coder.decode(encoded2);
|
|
|
|
// console.log({ decoded1, decoded2 });
|
|
|
|
// assert(Buffer.compare(encoded1, encoded2) === -1);
|
|
// assert.deepStrictEqual(data1, stripUndefined(decoded1));
|
|
// assert.deepStrictEqual(data2, stripUndefined(decoded2));
|
|
|
|
// function stripUndefined(object) {
|
|
// let newObject = {};
|
|
|
|
// for (let [ key, value ] of Object.entries(object)) {
|
|
// if (value !== undefined) {
|
|
// newObject[key] = value;
|
|
// }
|
|
// }
|
|
|
|
// return newObject;
|
|
// }
|