@chainsafe/ssz
Version:
Simple Serialize
99 lines • 4.21 kB
JavaScript
import { isCompositeType } from "../type/composite.js";
import { TreeViewDU } from "./abstract.js";
export class ContainerNodeStructTreeViewDU extends TreeViewDU {
type;
valueChanged = null;
_rootNode;
constructor(type, node) {
super();
this.type = type;
this._rootNode = node;
}
get node() {
return this._rootNode;
}
get cache() {
// biome-ignore lint/suspicious/useGetterReturn: There is no cache to return
return;
}
get value() {
return this.valueChanged ?? this._rootNode.value;
}
/**
* There are 2 cases:
* - normal commit() or hashTreeRoot(): hcByLevel is null, no need to compute root
* - batchHashTreeRoot(): hcByLevel is not null, need to compute root because this does not support HashComputation
*/
commit(_, hcByLevel = null) {
if (this.valueChanged !== null) {
const value = this.valueChanged;
this.valueChanged = null;
this._rootNode = this.type.value_toTree(value);
}
if (this._rootNode.h0 === null && hcByLevel !== null) {
// consumer is batchHashTreeRoot()
this._rootNode.rootHashObject;
}
}
clearCache() {
this.valueChanged = null;
}
}
export function getContainerTreeViewDUClass(type) {
class CustomContainerTreeViewDU extends ContainerNodeStructTreeViewDU {
}
// Dynamically define prototype methods
for (let index = 0; index < type.fieldsEntries.length; index++) {
const { fieldName, fieldType } = type.fieldsEntries[index];
// If the field type is basic, the value to get and set will be the actual 'struct' value (i.e. a JS number).
// The view must use the tree_getFromNode() and tree_setToNode() methods to persist the struct data to the node,
// and use the cached views array to store the new node.
if (fieldType.isBasic) {
Object.defineProperty(CustomContainerTreeViewDU.prototype, fieldName, {
configurable: false,
enumerable: true,
// TODO: Review the memory cost of this closures
get: function () {
return (this.valueChanged || this._rootNode.value)[fieldName];
},
set: function (value) {
if (this.valueChanged === null) {
this.valueChanged = this.type.clone(this._rootNode.value);
}
this.valueChanged[fieldName] = value;
},
});
}
// If the field type is composite, the value to get and set will be another TreeView. The parent TreeView must
// cache the view itself to retain the caches of the child view. To set a value the view must return a node to
// set it to the parent tree in the field gindex.
else if (isCompositeType(fieldType)) {
Object.defineProperty(CustomContainerTreeViewDU.prototype, fieldName, {
configurable: false,
enumerable: true,
// Returns TreeViewDU of fieldName
get: function () {
const value = this.valueChanged || this._rootNode.value;
return fieldType.toViewDU(value[fieldName]);
},
// Expects TreeViewDU of fieldName
set: function (view) {
if (this.valueChanged === null) {
this.valueChanged = this.type.clone(this._rootNode.value);
}
const value = fieldType.toValueFromViewDU(view);
this.valueChanged[fieldName] = value;
},
});
}
// Should never happen
else {
/* istanbul ignore next - unreachable code */
throw Error(`Unknown fieldType ${fieldType.typeName} for fieldName ${String(fieldName)}`);
}
}
// Change class name
Object.defineProperty(CustomContainerTreeViewDU, "name", { value: type.typeName, writable: false });
return CustomContainerTreeViewDU;
}
//# sourceMappingURL=containerNodeStruct.js.map