UNPKG

@chainsafe/ssz

Version:

Simple Serialize

96 lines 3.96 kB
import { concatGindices, getNode, toGindex } from "@chainsafe/persistent-merkle-tree"; import { value_cloneArray, value_defaultValueArray, value_equals, value_fromJsonArray, value_toJsonArray, } from "./arrayBasic.js"; import { CompositeType, LENGTH_GINDEX, isCompositeType } from "./composite.js"; /** * Array: ordered homogeneous collection */ export class ArrayType extends CompositeType { elementType; constructor(elementType, cachePermanentRootStruct) { super(cachePermanentRootStruct); this.elementType = elementType; } defaultValue() { return value_defaultValueArray(this.elementType, this.defaultLen); } // Proofs getPropertyType() { return this.elementType; } getPropertyGindex(prop) { if (typeof prop !== "number") { throw Error(`Invalid array index: ${prop}`); } const chunkIdx = Math.floor(prop / this.itemsPerChunk); return toGindex(this.depth, BigInt(chunkIdx)); } getIndexProperty(index) { return index; } tree_getLeafGindices(rootGindex, rootNode) { let length; if (this.isList) { if (!rootNode) { throw new Error("List type requires tree argument to get leaves"); } length = this.tree_getLength(rootNode); } else { // Vectors don't need a rootNode to return length length = this.tree_getLength(null); } const gindices = []; if (isCompositeType(this.elementType)) { // Underlying elements exist one per chunk // Iterate through chunk gindices, recursively fetching leaf gindices from each chunk const startIndex = toGindex(this.depth, BigInt(0)); const endGindex = startIndex + BigInt(length); const extendedStartIndex = concatGindices([rootGindex, startIndex]); if (this.elementType.fixedSize === null) { if (!rootNode) { /* istanbul ignore next - unreachable code */ throw new Error("Array of variable size requires tree argument to get leaves"); } // variable-length elements must pass the underlying subtrees to determine the length for (let gindex = startIndex, extendedGindex = extendedStartIndex; gindex < endGindex; gindex++, extendedGindex++) { gindices.push(...this.elementType.tree_getLeafGindices(extendedGindex, getNode(rootNode, gindex))); } } else { for (let i = 0, extendedGindex = extendedStartIndex; i < length; i++, extendedGindex++) { gindices.push(...this.elementType.tree_getLeafGindices(extendedGindex)); } } } // Basic else { const chunkCount = Math.ceil(length / this.itemsPerChunk); const startIndex = concatGindices([rootGindex, toGindex(this.depth, BigInt(0))]); const endGindex = startIndex + BigInt(chunkCount); for (let gindex = startIndex; gindex < endGindex; gindex++) { gindices.push(gindex); } } // include the length chunk if (this.isList) { gindices.push(concatGindices([rootGindex, LENGTH_GINDEX])); } return gindices; } // JSON fromJson(json) { // TODO: Do a better typesafe approach, all final classes of ArrayType implement ArrayProps // There are multiple tests that cover this path for all clases return value_fromJsonArray(this.elementType, json, this); } toJson(value) { return value_toJsonArray(this.elementType, value, this); } clone(value) { return value_cloneArray(this.elementType, value); } equals(a, b) { return value_equals(this.elementType, a, b); } } //# sourceMappingURL=array.js.map