@chainsafe/ssz
Version:
Simple Serialize
113 lines • 4.34 kB
JavaScript
import { maxChunksToDepth } from "../util/merkleize.js";
import { namedClass } from "../util/named.js";
import { ArrayBasicTreeView } from "../view/arrayBasic.js";
import { ArrayBasicTreeViewDU } from "../viewDU/arrayBasic.js";
import { ArrayType } from "./array.js";
import { tree_deserializeFromBytesArrayBasic, tree_serializeToBytesArrayBasic, value_deserializeFromBytesArrayBasic, value_serializeToBytesArrayBasic, } from "./arrayBasic.js";
/**
* Vector: Ordered fixed-length homogeneous collection, with N values
*
* Array of Basic type:
* - Basic types are max 32 bytes long so multiple values may be packed in the same node.
* - Basic types are never returned in a view wrapper, but their value representation
*/
export class VectorBasicType extends ArrayType {
elementType;
length;
typeName;
itemsPerChunk;
depth;
chunkDepth;
maxChunkCount;
fixedSize;
minSize;
maxSize;
isList = false;
isViewMutable = true;
defaultLen;
constructor(elementType, length, opts) {
super(elementType);
this.elementType = elementType;
this.length = length;
if (!elementType.isBasic)
throw Error("elementType must be basic");
if (length === 0)
throw Error("Vector length must be > 0");
this.typeName = opts?.typeName ?? `Vector[${elementType.typeName}, ${length}]`;
// TODO Check that itemsPerChunk is an integer
this.itemsPerChunk = 32 / elementType.byteLength;
this.maxChunkCount = Math.ceil((length * elementType.byteLength) / 32);
this.chunkDepth = maxChunksToDepth(this.maxChunkCount);
this.depth = this.chunkDepth;
this.fixedSize = length * elementType.byteLength;
this.minSize = this.fixedSize;
this.maxSize = this.fixedSize;
this.defaultLen = length;
this.blocksBuffer = new Uint8Array(Math.ceil(this.maxChunkCount / 2) * 64);
}
static named(elementType, limit, opts) {
return new (namedClass(VectorBasicType, opts.typeName))(elementType, limit, opts);
}
getView(tree) {
return new ArrayBasicTreeView(this, tree);
}
getViewDU(node, cache) {
// cache type should be validated (if applicate) in the view
// biome-ignore lint/suspicious/noExplicitAny: We explicity need to use `any` here
return new ArrayBasicTreeViewDU(this, node, cache);
}
commitView(view) {
return view.node;
}
commitViewDU(view, hcOffset = 0, hcByLevel = null) {
view.commit(hcOffset, hcByLevel);
return view.node;
}
cacheOfViewDU(view) {
return view.cache;
}
// Serialization + deserialization
value_serializedSize() {
return this.fixedSize;
}
value_serializeToBytes(output, offset, value) {
return value_serializeToBytesArrayBasic(this.elementType, this.length, output, offset, value);
}
value_deserializeFromBytes(data, start, end) {
return value_deserializeFromBytesArrayBasic(this.elementType, data, start, end, this);
}
tree_serializedSize() {
return this.fixedSize;
}
tree_serializeToBytes(output, offset, node) {
return tree_serializeToBytesArrayBasic(this.elementType, this.length, this.depth, output, offset, node);
}
tree_deserializeFromBytes(data, start, end) {
return tree_deserializeFromBytesArrayBasic(this.elementType, this.depth, data, start, end, this);
}
// Helpers for TreeView
tree_getLength() {
return this.length;
}
tree_setLength() {
// Vector's length is immutable, ignore this call
}
tree_getChunksNode(node) {
return node;
}
tree_chunksNodeOffset() {
return 0;
}
tree_setChunksNode(_rootNode, chunksNode) {
return chunksNode;
}
// Merkleization
getBlocksBytes(value) {
const uint8Array = this.blocksBuffer.subarray(0, this.fixedSize);
const dataView = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
value_serializeToBytesArrayBasic(this.elementType, this.length, { uint8Array, dataView }, 0, value);
// remaining bytes from this.fixedSize to this.blocksBuffer.length must be zeroed
return this.blocksBuffer;
}
}
//# sourceMappingURL=vectorBasic.js.map