UNPKG

@aeternity/aepp-calldata

Version:
132 lines (128 loc) 3.99 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _PrimitivesEncoder = _interopRequireDefault(require("../PrimitivesEncoder.cjs")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const TYPE2SIZE = { uint_32: 4, uint_64: 8, account_pubkey: 32, key_block_hash: 32, micro_block_hash: 32, block_pof_hash: 32, block_tx_hash: 32, block_state_hash: 32, signature: 64, pow: 168 }; class FieldsEncoder { constructor(fieldEncoder) { this.fieldEncoder = fieldEncoder; this.primEncoder = new _PrimitivesEncoder.default(); } /** * Encode data fields according to a template * * @param {object} data - An object with field => value items * @param {object} template - An object with field => type items * @returns {array} A poisioned array of encoded fields with preserved order */ encodeFields(data, template) { const chunks = []; for (const field in template) { if (Object.hasOwn(template, field)) { const type = template[field]; const encoded = this.#encodeField(type, data[field]); chunks.push(encoded); } } return chunks; } /** * Decode data fields according to a template * * @param {array} data - An array with positioned values according to the template * @param {object} template - An object with field => type items * @returns {object} An object with decoded field => value items */ decodeFields(data, template) { const chunks = {}; let idx = 0; for (const field in template) { if (Object.hasOwn(template, field)) { const type = template[field]; chunks[field] = this.#decodeField(type, data[idx]); idx++; } } return chunks; } // Split data stream into fields based on their size splitFields(stream, template) { const fields = []; let idx = 0; for (const field in template) { if (Object.hasOwn(template, field)) { const size = this.#sizeOf(template[field]); fields.push(stream.slice(idx, idx + size)); idx += size; } } return fields; } #sizeOf(type) { // most (all?) chain objects does not have fixed size // thus they can be nested in other objects only as last field // size of Infinity would split all the rest bytes to that field if (type === 'chain_object') { return Infinity; } if (Object.getPrototypeOf(type) === Object.prototype) { let objectSize = 0; for (const field in type.template) { if (Object.hasOwn(type.template, field)) { objectSize += this.#sizeOf(type.template[field]); } } return objectSize; } if (!TYPE2SIZE.hasOwnProperty(type)) { throw new Error(`Unknown size of type "${type}"`); } return TYPE2SIZE[type]; } #encodeField(typeInfo, value) { if (Array.isArray(typeInfo)) { return value.map(v => this.#encodeField(typeInfo[0], v)); } if (Object.getPrototypeOf(typeInfo) === Object.prototype) { const { template } = typeInfo; return new Uint8Array(this.encodeFields(value, template).flatMap(e => [...e])); } if (this.primEncoder.supports(typeInfo)) { return this.primEncoder.encode(typeInfo, value); } return this.fieldEncoder.encode(typeInfo, value); } #decodeField(typeInfo, value) { if (Array.isArray(typeInfo)) { return value.map(v => this.#decodeField(typeInfo[0], v)); } if (Object.getPrototypeOf(typeInfo) === Object.prototype) { const { template } = typeInfo; const objectFields = this.splitFields(value, template); return this.decodeFields(objectFields, template); } if (this.primEncoder.supports(typeInfo)) { return this.primEncoder.decode(typeInfo, value); } return this.fieldEncoder.decode(typeInfo, value); } } var _default = exports.default = FieldsEncoder;