@aggris2/ssz
Version:
Simple Serialize
149 lines • 5.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StringBigintType = void 0;
const persistent_merkle_tree_1 = require("@chainsafe/persistent-merkle-tree");
const basic_1 = require("./basic");
const BIGINT_2_POW_64 = BigInt(2) ** BigInt(64);
const BIGINT_2_POW_128 = BigInt(2) ** BigInt(128);
const BIGINT_2_POW_192 = BigInt(2) ** BigInt(192);
/**
* Uint: N-bit unsigned integer (where N in [8, 16, 32, 64, 128, 256])
* - Notation: uintN
*
* UintBigint is represented as the Javascript primitive value 'BigInt'.
*
* The BigInt type is a numeric primitive in JavaScript that can represent integers with arbitrary precision.
* With BigInts, you can safely store and operate on large integers even beyond the safe integer limit for Numbers.
*
* As of 2021 performance of 'Number' is extremely faster than 'BigInt'. For Uint values under 53 bits use UintNumber.
* For other values that may exceed 53 bits, use UintBigint.
*/
class StringBigintType extends basic_1.BasicType {
constructor(byteLength) {
super();
this.byteLength = byteLength;
if (byteLength > 32) {
throw Error("UintBigint byteLength limit is 32");
}
if (Math.log2(byteLength) % 1 !== 0) {
throw Error("byteLength must be a power of 2");
}
this.typeName = `string`;
this.byteLength = byteLength;
this.itemsPerChunk = 32 / this.byteLength;
this.fixedSize = byteLength;
this.minSize = byteLength;
this.maxSize = byteLength;
}
defaultValue() {
return "0";
}
// Serialization + deserialization
value_serializeToBytes({ dataView }, offset, v) {
let value = BigInt(v);
switch (this.byteLength) {
case 1:
dataView.setInt8(offset, Number(value));
break;
case 2:
dataView.setUint16(offset, Number(value), true);
break;
case 4:
dataView.setUint32(offset, Number(value), true);
break;
case 8:
dataView.setBigUint64(offset, value, true);
break;
default: {
for (let i = 0; i < this.byteLength; i += 8) {
if (i > 0)
value = value / BIGINT_2_POW_64;
const lo = BigInt.asUintN(64, value);
dataView.setBigUint64(offset + i, lo, true);
}
}
}
return offset + this.byteLength;
}
value_deserializeFromBytes({ dataView }, start, end) {
const size = end - start;
if (size !== this.byteLength) {
throw Error(`Invalid size ${size} expected ${this.byteLength}`);
}
// Note: pre-assigning the right function at the constructor to avoid this switch is not faster
switch (this.byteLength) {
case 1:
return BigInt(dataView.getUint8(start)).toString();
case 2:
return BigInt(dataView.getUint16(start, true)).toString();
case 4:
return BigInt(dataView.getUint32(start, true)).toString();
case 8:
return dataView.getBigUint64(start, true).toString();
case 16: {
const a = dataView.getBigUint64(start, true);
const b = dataView.getBigUint64(start + 8, true);
return (b * BIGINT_2_POW_64 + a).toString();
}
case 32: {
const a = dataView.getBigUint64(start, true);
const b = dataView.getBigUint64(start + 8, true);
const c = dataView.getBigUint64(start + 16, true);
const d = dataView.getBigUint64(start + 24, true);
return (d * BIGINT_2_POW_192 + c * BIGINT_2_POW_128 + b * BIGINT_2_POW_64 + a).toString();
}
}
}
tree_serializeToBytes(output, offset, node) {
const value = node.getUintBigint(this.byteLength, 0).toString();
this.value_serializeToBytes(output, offset, value);
return offset + this.byteLength;
}
tree_deserializeFromBytes(data, start, end) {
const size = end - start;
if (size !== this.byteLength) {
throw Error(`Invalid size ${size} expected ${this.byteLength}`);
}
const value = BigInt(this.value_deserializeFromBytes(data, start, end));
const node = persistent_merkle_tree_1.LeafNode.fromZero();
node.setUintBigint(this.byteLength, 0, value);
return node;
}
// Fast Tree access
tree_getFromNode(leafNode) {
return leafNode.getUintBigint(this.byteLength, 0).toString();
}
/** Mutates node to set value */
tree_setToNode(leafNode, value) {
this.tree_setToPackedNode(leafNode, 0, value);
}
/** EXAMPLE of `tree_getFromNode` */
tree_getFromPackedNode(leafNode, index) {
const offsetBytes = this.byteLength * (index % this.itemsPerChunk);
return leafNode.getUintBigint(this.byteLength, offsetBytes).toString();
}
/** Mutates node to set value */
tree_setToPackedNode(leafNode, index, v) {
let value = BigInt(v);
const offsetBytes = this.byteLength * (index % this.itemsPerChunk);
// TODO: Not-optimized, copy pasted from UintNumberType
leafNode.setUintBigint(this.byteLength, offsetBytes, value);
}
// JSON
fromJson(json) {
if (typeof json === "string") {
return json;
}
else if (typeof json === "number") {
return BigInt(json).toString();
}
else {
throw Error(`JSON invalid type ${typeof json} expected bigint`);
}
}
toJson(value) {
return value;
}
}
exports.StringBigintType = StringBigintType;
//# sourceMappingURL=string.js.map