import { makeTuple } from '@aztec/foundation/array';
import { Fr } from '@aztec/foundation/fields';
import { schemas } from '@aztec/foundation/schemas';
import { assertLength, deserializeArrayFromVector, serializeArrayOfBufferableToVector, } from '@aztec/foundation/serialize';
import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
/**
 * Contains functionality to compute and serialize/deserialize a sibling path.
 * E.g. Sibling path for a leaf at index 3 in a tree of depth 3 consists of:
 *      d0:                                            [ root ]
 *      d1:                      [ ]                                               [*]
 *      d2:         [*]                      [ ]                       [ ]                     [ ]
 *      d3:   [ ]         [ ]          [*]         [ ]           [ ]         [ ]          [ ]        [ ].
 *
 *      And the elements would be ordered as: [ leaf_at_index_2, node_at_level_2_index_0, node_at_level_1_index_1 ].
 */
export class SiblingPath {
    /**
     * Constructor.
     * @param pathSize - The size of the sibling path.
     * @param path - The sibling path data.
     */
    constructor(
    /** Size of the sibling path (number of fields it contains). */
    pathSize, 
    /** The sibling path data. */
    path) {
        this.pathSize = pathSize;
        this.data = assertLength(path, pathSize);
    }
    static get schema() {
        return schemas.Buffer.transform(b => SiblingPath.fromBuffer(b));
    }
    static schemaFor(size) {
        return schemas.Buffer.transform(b => SiblingPath.fromBuffer(b)).refine(path => path.pathSize === size, path => ({ message: `Expected sibling path size ${size} but got ${path.pathSize}` }));
    }
    toJSON() {
        return this.toBuffer();
    }
    /**
     * Returns sibling path hashed up from the a element.
     * @param size - The number of elements in a given path.
     * @param zeroElement - Value of the zero element.
     * @param hasher - Implementation of a hasher interface.
     * @returns A sibling path hashed up from a zero element.
     */
    static ZERO(size, zeroElement, hasher) {
        const bufs = [];
        let current = zeroElement;
        for (let i = 0; i < size; ++i) {
            bufs.push(current);
            current = hasher.hash(current, current);
        }
        return new SiblingPath(size, bufs);
    }
    static random(number) {
        const data = Array.from({ length: number }, () => Fr.random().toBuffer());
        return new SiblingPath(number, data);
    }
    /**
     * Serializes this SiblingPath object to a buffer.
     * @returns The buffer representation of this object.
     */
    toBuffer() {
        return serializeArrayOfBufferableToVector(this.data);
    }
    /**
     * Returns the path buffer underlying the sibling path.
     * @returns The Buffer array representation of this object.
     */
    toBufferArray() {
        return this.data;
    }
    /**
     * Convert the Sibling Path object into an array of field elements.
     * @returns The field array representation of this object.
     */
    toFields() {
        return this.data.map(buf => Fr.fromBuffer(buf));
    }
    /**
     * Convert Sibling Path object into a tuple of field elements.
     * @returns A tuple representation of the sibling path.
     */
    toTuple() {
        const array = this.toFields();
        return makeTuple(array.length, i => array[i], 0);
    }
    /**
     * Deserializes a SiblingPath from a buffer.
     * @param buf - A buffer containing the buffer representation of SiblingPath.
     * @param offset - An offset to start deserializing from.
     * @returns A SiblingPath object.
     */
    static fromBuffer(buf, offset = 0) {
        const { elem } = SiblingPath.deserialize(buf, offset);
        return elem;
    }
    /**
     * Deserializes a SiblingPath object from a slice of a part of a buffer and returns the amount of bytes advanced.
     * @param buf - A buffer representation of the sibling path.
     * @param offset - An offset to start deserializing from.
     * @returns The deserialized sibling path and the number of bytes advanced.
     */
    static deserialize(buf, offset = 0) {
        const deserializePath = (buf, offset) => ({
            elem: buf.slice(offset, offset + 32),
            adv: 32,
        });
        const { elem, adv } = deserializeArrayFromVector(deserializePath, buf, offset);
        const size = elem.length;
        return { elem: new SiblingPath(size, elem), adv };
    }
    /**
     * Serializes this SiblingPath object to a hex string representation.
     * @returns A hex string representation of the sibling path.
     */
    toString() {
        return bufferToHex(this.toBuffer());
    }
    /**
     * Deserializes a SiblingPath object from a hex string representation.
     * @param repr - A hex string representation of the sibling path.
     * @returns A SiblingPath object.
     */
    static fromString(repr) {
        return SiblingPath.fromBuffer(hexToBuffer(repr));
    }
    /**
     * Generate a subtree path from the current sibling path.
     * @param subtreeHeight - The size of the subtree that we are getting the path for.
     * @returns A new sibling path that is the for the requested subtree.
     */
    getSubtreeSiblingPath(subtreeHeight) {
        // Drop the size of the subtree from the path, and return the rest.
        const subtreeData = this.data.slice(subtreeHeight);
        const subtreePathSize = (this.pathSize - subtreeHeight);
        return new SiblingPath(subtreePathSize, subtreeData);
    }
}
//# sourceMappingURL=data:application/json;base64, 