@chainsafe/ssz
Version:
Simple Serialize
74 lines • 3.67 kB
JavaScript
import { LeafNode, getNodeAtDepth, setNodesAtDepth, treeZeroAfterIndex, zeroNode, } from "@chainsafe/persistent-merkle-tree";
import { tree_serializeToBytesArrayBasic } from "../type/arrayBasic.js";
import { ArrayBasicTreeViewDU } from "./arrayBasic.js";
export class ListBasicTreeViewDU extends ArrayBasicTreeViewDU {
type;
_rootNode;
constructor(type, _rootNode, cache) {
super(type, _rootNode, cache);
this.type = type;
this._rootNode = _rootNode;
}
/**
* Adds one value element at the end of the array and adds 1 to the un-commited ViewDU length
*/
push(value) {
if (this._length >= this.type.limit) {
throw Error("Error pushing over limit");
}
// Mutate length before .set()
this.dirtyLength = true;
const index = this._length++;
// If in new node..
if (index % this.type.itemsPerChunk === 0) {
// Set a zero node to the nodes array to avoid a navigation downwards in .set()
const chunkIndex = Math.floor(index / this.type.itemsPerChunk);
this.nodes[chunkIndex] = zeroNode(0);
}
this.set(index, value);
}
/**
* Returns a new ListBasicTreeViewDU instance with the values from 0 to `index`.
* To achieve it, rebinds the underlying tree zero-ing all nodes right of `chunkIindex`.
* Also set all value right of `index` in the same chunk to 0.
*/
sliceTo(index) {
if (index < 0) {
throw new Error(`Does not support sliceTo() with negative index ${index}`);
}
// Commit before getting rootNode to ensure all pending data is in the rootNode
this.commit();
// All nodes beyond length are already zero
if (index >= this._length - 1) {
return this;
}
const rootNode = this._rootNode;
const chunkIndex = Math.floor(index / this.type.itemsPerChunk);
const nodePrev = (this.nodes[chunkIndex] ?? getNodeAtDepth(rootNode, this.type.depth, chunkIndex));
// we can't set remaining items in the same chunk to 0 with tree_setToPackedNode api due to setBitwiseOR in UintNumberType
// instead, we set the same value in nodePrev up until index
const nodeChanged = LeafNode.fromZero();
for (let i = chunkIndex * this.type.itemsPerChunk; i <= index; i++) {
const prevValue = this.type.elementType.tree_getFromPackedNode(nodePrev, i);
this.type.elementType.tree_setToPackedNode(nodeChanged, i, prevValue);
}
const chunksNode = this.type.tree_getChunksNode(this._rootNode);
let newChunksNode = setNodesAtDepth(chunksNode, this.type.chunkDepth, [chunkIndex], [nodeChanged]);
// also do the treeZeroAfterIndex operation on the chunks tree
newChunksNode = treeZeroAfterIndex(newChunksNode, this.type.chunkDepth, chunkIndex);
// Must set new length and commit to tree to restore the same tree at that index
const newLength = index + 1;
const newRootNode = this.type.tree_setChunksNode(rootNode, newChunksNode, newLength);
return this.type.getViewDU(newRootNode);
}
/**
* Same method to `type/listBasic.ts` leveraging cached nodes.
*/
serializeToBytes(output, offset) {
this.commit();
const { nodes, nodesPopulated } = this.cache;
const chunksNode = this.type.tree_getChunksNode(this._rootNode);
return tree_serializeToBytesArrayBasic(this.type.elementType, this._length, this.type.chunkDepth, output, offset, chunksNode, nodesPopulated ? nodes : null);
}
}
//# sourceMappingURL=listBasic.js.map