// This file has been generated by structbuf. Do not modify it!
import * as base from '~/common/network/structbuf/base.js';
import type * as types from '~/common/types.js';
import * as utils from '../utils.js';

/**
 * Contains a mediator message payload.
 *
 * Direction: Client <-> Server
 */
export interface ContainerLike {
    /**
     * Identifies the payload type contained in the `payload` field.
     *
     * Chat server proxying:
     *   - `0x00`: [`proxy`](ref:payload.proxy)
     *
     * Handshake:
     *   - `0x10`: `d2m.ServerHello`
     *   - `0x11`: `d2m.ClientHello`
     *   - `0x12`: `d2m.ServerInfo`
     *
     * States:
     *   - `0x20`: `d2m.ReflectionQueueDry`
     *   - `0x21`: `d2m.RolePromotedToLeader`
     *
     * Device management:
     *   - `0x30`: `d2m.GetDevicesInfo`
     *   - `0x31`: `d2m.DevicesInfo`
     *   - `0x32`: `d2m.DropDevice`
     *   - `0x33`: `d2m.DropDeviceAck`
     *   - `0x34`: `d2m.SetSharedDeviceData`
     *
     * Transactions:
     *   - `0x40`: `d2m.BeginTransaction`
     *   - `0x41`: `d2m.BeginTransactionAck`
     *   - `0x42`: `d2m.CommitTransaction`
     *   - `0x43`: `d2m.CommitTransactionAck`
     *   - `0x44`: `d2m.TransactionRejected`
     *   - `0x45`: `d2m.TransactionEnded`
     *
     * Reflection:
     *   - `0x80`: [`reflect`](ref:payload.reflect)
     *   - `0x81`: [`reflect-ack`](ref:payload.reflect-ack)
     *   - `0x82`: [`reflected`](ref:payload.reflected)
     *   - `0x83`: [`reflected-ack`](ref:payload.reflected-ack)
     */
    readonly type: types.u8;

    /**
     * Should be set to all `0`s and ignored by the receiver.
     */
    readonly reserved: Uint8Array;

    /**
     * Message payload. Needs to be parsed according to the `type` field.
     */
    readonly payload: Uint8Array;
}

/**
 * Encodable of {@link ContainerLike}.
 */
interface ContainerEncodable_ {
    /**
     * 'type' field value or encoder. See {@link ContainerLike#type} for
     * the field's description.
     */
    readonly type: types.u8;

    /**
     * 'reserved' field value or encoder. See {@link ContainerLike#reserved} for
     * the field's description.
     */
    readonly reserved: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'payload' field value or encoder. See {@link ContainerLike#payload} for
     * the field's description.
     */
    readonly payload: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ContainerEncodable.
 */
export type ContainerEncodable = types.WeakOpaque<
    ContainerEncodable_,
    {readonly ContainerEncodable: unique symbol}
>;

/** @inheritdoc */
export class Container extends base.Struct implements ContainerLike {
    private readonly _array: Uint8Array;

    /**
     * Create a Container from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a container struct from an array.
     *
     * @param array Array to decode from.
     * @returns Container instance.
     */
    public static decode(array: Uint8Array): Container {
        return new Container(array);
    }

    /**
     * Encode a container struct into an array.
     *
     * @param struct ContainerEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ContainerEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        let offset = 4;

        // Encode `type`
        array[0] = struct.type;

        // Encode `reserved`
        utils.encodeBytes(struct.reserved, array, 1);

        // Encode `payload`
        offset += utils.encodeBytes(struct.payload, array, offset);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a container struct into an
     * array.
     *
     * @param struct ContainerEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ContainerEncodable, 'byteLength'>,
    ): types.u53 {
        let offset = 4;
        offset += utils.getByteLength(struct.payload);
        return offset;
    }

    /**
     * 'type' field accessor. See {@link ContainerLike#type} for the
     * field's description.
     */
    public get type(): types.u8 {
        return utils.unwrap(this._array[0]);
    }

    /**
     * 'reserved' field accessor. See {@link ContainerLike#reserved} for the
     * field's description.
     */
    public get reserved(): Uint8Array {
        const offset = 1;
        return this._array.subarray(offset, offset + 3);
    }

    /**
     * 'payload' field accessor. See {@link ContainerLike#payload} for the
     * field's description.
     */
    public get payload(): Uint8Array {
        return this._array.subarray(4);
    }

    /**
     * Create a snapshot of ContainerLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ContainerLike snapshot.
     */
    public snapshot(): ContainerLike {
        return {
            type: this.type,
            reserved: this.reserved,
            payload: this.payload,
        };
    }

    /**
     * Create a clone of ContainerLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ContainerLike clone.
     */
    public clone(): Container {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new Container(array);
    }
}

/**
 * Proxy a message to/from the chat server.
 */
export interface ProxyLike {
    /**
     * The data to be proxied to/from the chat server, encrypted by
     * following the Chat Server Protocol.
     */
    readonly data: Uint8Array;
}

/**
 * Encodable of {@link ProxyLike}.
 */
interface ProxyEncodable_ {
    /**
     * 'data' field value or encoder. See {@link ProxyLike#data} for
     * the field's description.
     */
    readonly data: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ProxyEncodable.
 */
export type ProxyEncodable = types.WeakOpaque<
    ProxyEncodable_,
    {readonly ProxyEncodable: unique symbol}
>;

/** @inheritdoc */
export class Proxy extends base.Struct implements ProxyLike {
    private readonly _array: Uint8Array;

    /**
     * Create a Proxy from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
    }

    /**
     * Decode a proxy struct from an array.
     *
     * @param array Array to decode from.
     * @returns Proxy instance.
     */
    public static decode(array: Uint8Array): Proxy {
        return new Proxy(array);
    }

    /**
     * Encode a proxy struct into an array.
     *
     * @param struct ProxyEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ProxyEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        let offset = 0;

        // Encode `data`
        offset += utils.encodeBytes(struct.data, array, offset);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a proxy struct into an
     * array.
     *
     * @param struct ProxyEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(struct: types.EncoderPick<ProxyEncodable, 'byteLength'>): types.u53 {
        let offset = 0;
        offset += utils.getByteLength(struct.data);
        return offset;
    }

    /**
     * 'data' field accessor. See {@link ProxyLike#data} for the
     * field's description.
     */
    public get data(): Uint8Array {
        return this._array.subarray(0);
    }

    /**
     * Create a snapshot of ProxyLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ProxyLike snapshot.
     */
    public snapshot(): ProxyLike {
        return {
            data: this.data,
        };
    }

    /**
     * Create a clone of ProxyLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ProxyLike clone.
     */
    public clone(): Proxy {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new Proxy(array);
    }
}

/**
 * Reflect a message into the reflection queue of all other devices.
 *
 * Direction: Client --> Server
 */
export interface ReflectLike {
    /**
     * Contains the byte length of all fields prior to the `envelope` field
     * (`8` at the moment).
     */
    readonly headerLength: types.u8;

    /**
     * Should be set to `0` and ignored by the receiver.
     */
    readonly reserved: types.u8;

    /**
     * Flags:
     *
     * - `0x00_01`: Ephemeral marker. The server will forward the message only
     *   to devices that are currently connected while still maintaining
     *   the order of the reflection queue. If the receiving device
     *   disconnects before the ephemeral message was forwarded to it, that
     *   message should be discarded. An acknowledgement must not be sent.
     */
    readonly flags: types.u16;

    /**
     * Unique number (per connection) used for acknowledgement.
     */
    readonly reflectId: types.u32;

    /**
     * The protobuf-encoded and encrypted data to be reflected, encrypted by
     * `DGRK.secret` and prefixed with a random nonce. See `d2d.proto` for
     * details on the `Envelope` contents.
     */
    readonly envelope: Uint8Array;
}

/**
 * Encodable of {@link ReflectLike}.
 */
interface ReflectEncodable_ {
    /**
     * 'header-length' field value or encoder. See {@link ReflectLike#headerLength} for
     * the field's description.
     */
    readonly headerLength: types.u8;

    /**
     * 'reserved' field value or encoder. See {@link ReflectLike#reserved} for
     * the field's description.
     */
    readonly reserved: types.u8;

    /**
     * 'flags' field value or encoder. See {@link ReflectLike#flags} for
     * the field's description.
     */
    readonly flags: types.u16;

    /**
     * 'reflect-id' field value or encoder. See {@link ReflectLike#reflectId} for
     * the field's description.
     */
    readonly reflectId: types.u32;

    /**
     * 'envelope' field value or encoder. See {@link ReflectLike#envelope} for
     * the field's description.
     */
    readonly envelope: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ReflectEncodable.
 */
export type ReflectEncodable = types.WeakOpaque<
    ReflectEncodable_,
    {readonly ReflectEncodable: unique symbol}
>;

/** @inheritdoc */
export class Reflect extends base.Struct implements ReflectLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a Reflect from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a reflect struct from an array.
     *
     * @param array Array to decode from.
     * @returns Reflect instance.
     */
    public static decode(array: Uint8Array): Reflect {
        return new Reflect(array);
    }

    /**
     * Encode a reflect struct into an array.
     *
     * @param struct ReflectEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ReflectEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);
        let offset = 8;

        // Encode `header-length`
        array[0] = struct.headerLength;

        // Encode `reserved`
        array[1] = struct.reserved;

        // Encode `flags`
        view.setUint16(2, struct.flags, true);

        // Encode `reflect-id`
        view.setUint32(4, struct.reflectId, true);

        // Encode `envelope`
        offset += utils.encodeBytes(struct.envelope, array, offset);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a reflect struct into an
     * array.
     *
     * @param struct ReflectEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(struct: types.EncoderPick<ReflectEncodable, 'byteLength'>): types.u53 {
        let offset = 8;
        offset += utils.getByteLength(struct.envelope);
        return offset;
    }

    /**
     * 'header-length' field accessor. See {@link ReflectLike#headerLength} for the
     * field's description.
     */
    public get headerLength(): types.u8 {
        return utils.unwrap(this._array[0]);
    }

    /**
     * 'reserved' field accessor. See {@link ReflectLike#reserved} for the
     * field's description.
     */
    public get reserved(): types.u8 {
        return utils.unwrap(this._array[1]);
    }

    /**
     * 'flags' field accessor. See {@link ReflectLike#flags} for the
     * field's description.
     */
    public get flags(): types.u16 {
        return this._view.getUint16(2, true);
    }

    /**
     * 'reflect-id' field accessor. See {@link ReflectLike#reflectId} for the
     * field's description.
     */
    public get reflectId(): types.u32 {
        return this._view.getUint32(4, true);
    }

    /**
     * 'envelope' field accessor. See {@link ReflectLike#envelope} for the
     * field's description.
     */
    public get envelope(): Uint8Array {
        return this._array.subarray(8);
    }

    /**
     * Create a snapshot of ReflectLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ReflectLike snapshot.
     */
    public snapshot(): ReflectLike {
        return {
            headerLength: this.headerLength,
            reserved: this.reserved,
            flags: this.flags,
            reflectId: this.reflectId,
            envelope: this.envelope,
        };
    }

    /**
     * Create a clone of ReflectLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ReflectLike clone.
     */
    public clone(): Reflect {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new Reflect(array);
    }
}

/**
 * Acknowledges that a message to be reflected to all other devices has been
 * stored in their respective reflection queues.
 *
 * Direction: Client <-- Server
 */
export interface ReflectAckLike {
    /**
     * Should be set to all `0`s and ignored by the receiver.
     */
    readonly reserved: Uint8Array;

    /**
     * Refers to the `Reflect ID` as sent in the `Reflect` message.
     */
    readonly reflectId: types.u32;

    /**
     * Unix-ish timestamp in milliseconds when the message has been stored
     * in the reflection queue of the mediator server.
     */
    readonly timestamp: types.u64;
}

/**
 * Encodable of {@link ReflectAckLike}.
 */
interface ReflectAckEncodable_ {
    /**
     * 'reserved' field value or encoder. See {@link ReflectAckLike#reserved} for
     * the field's description.
     */
    readonly reserved: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'reflect-id' field value or encoder. See {@link ReflectAckLike#reflectId} for
     * the field's description.
     */
    readonly reflectId: types.u32;

    /**
     * 'timestamp' field value or encoder. See {@link ReflectAckLike#timestamp} for
     * the field's description.
     */
    readonly timestamp: types.u64;
}

/**
 * New-type for ReflectAckEncodable.
 */
export type ReflectAckEncodable = types.WeakOpaque<
    ReflectAckEncodable_,
    {readonly ReflectAckEncodable: unique symbol}
>;

/** @inheritdoc */
export class ReflectAck extends base.Struct implements ReflectAckLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a ReflectAck from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a reflect-ack struct from an array.
     *
     * @param array Array to decode from.
     * @returns ReflectAck instance.
     */
    public static decode(array: Uint8Array): ReflectAck {
        return new ReflectAck(array);
    }

    /**
     * Encode a reflect-ack struct into an array.
     *
     * @param struct ReflectAckEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ReflectAckEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);

        // Encode `reserved`
        utils.encodeBytes(struct.reserved, array, 0);

        // Encode `reflect-id`
        view.setUint32(4, struct.reflectId, true);

        // Encode `timestamp`
        view.setBigUint64(8, struct.timestamp, true);

        return array.subarray(0, 16);
    }

    /**
     * Get the amount of bytes that would be written when encoding a reflect-ack struct into an
     * array.
     *
     * @param struct ReflectAckEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ReflectAckEncodable, 'byteLength'>,
    ): types.u53 {
        return 16;
    }

    /**
     * 'reserved' field accessor. See {@link ReflectAckLike#reserved} for the
     * field's description.
     */
    public get reserved(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 4);
    }

    /**
     * 'reflect-id' field accessor. See {@link ReflectAckLike#reflectId} for the
     * field's description.
     */
    public get reflectId(): types.u32 {
        return this._view.getUint32(4, true);
    }

    /**
     * 'timestamp' field accessor. See {@link ReflectAckLike#timestamp} for the
     * field's description.
     */
    public get timestamp(): types.u64 {
        return this._view.getBigUint64(8, true);
    }

    /**
     * Create a snapshot of ReflectAckLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ReflectAckLike snapshot.
     */
    public snapshot(): ReflectAckLike {
        return {
            reserved: this.reserved,
            reflectId: this.reflectId,
            timestamp: this.timestamp,
        };
    }

    /**
     * Create a clone of ReflectAckLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ReflectAckLike clone.
     */
    public clone(): ReflectAck {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ReflectAck(array);
    }
}

/**
 * Deliver a message from the device's reflection queue.
 *
 * Direction: Client <-- Server
 */
export interface ReflectedLike {
    /**
     * Contains the byte length of all fields prior to the `envelope` field
     * (`16` at the moment).
     */
    readonly headerLength: types.u8;

    /**
     * Should be set to `0` and ignored by the receiver.
     */
    readonly reserved: types.u8;

    /**
     * Flags:
     *
     * - `0x00_01`: Ephemeral marker. The sending device requested this
     *   message to only be reflected to devices that are currently online.
     *   An acknowledgement must not be sent.
     */
    readonly flags: types.u16;

    /**
     * Monotonically increasing unique number (per device slot) used for
     * acknowledgement. May wrap.
     */
    readonly reflectedId: types.u32;

    /**
     * Unix-ish timestamp in milliseconds when the message has been stored
     * in the reflection queue of the mediator server.
     */
    readonly timestamp: types.u64;

    /**
     * The protobuf-encoded and encrypted data to be reflected, encrypted by
     * `DGRK.secret` and prefixed with a random nonce. See `d2d.proto` for
     * details on the `Envelope` contents.
     */
    readonly envelope: Uint8Array;
}

/**
 * Encodable of {@link ReflectedLike}.
 */
interface ReflectedEncodable_ {
    /**
     * 'header-length' field value or encoder. See {@link ReflectedLike#headerLength} for
     * the field's description.
     */
    readonly headerLength: types.u8;

    /**
     * 'reserved' field value or encoder. See {@link ReflectedLike#reserved} for
     * the field's description.
     */
    readonly reserved: types.u8;

    /**
     * 'flags' field value or encoder. See {@link ReflectedLike#flags} for
     * the field's description.
     */
    readonly flags: types.u16;

    /**
     * 'reflected-id' field value or encoder. See {@link ReflectedLike#reflectedId} for
     * the field's description.
     */
    readonly reflectedId: types.u32;

    /**
     * 'timestamp' field value or encoder. See {@link ReflectedLike#timestamp} for
     * the field's description.
     */
    readonly timestamp: types.u64;

    /**
     * 'envelope' field value or encoder. See {@link ReflectedLike#envelope} for
     * the field's description.
     */
    readonly envelope: Uint8Array | types.ByteLengthEncoder;
}

/**
 * New-type for ReflectedEncodable.
 */
export type ReflectedEncodable = types.WeakOpaque<
    ReflectedEncodable_,
    {readonly ReflectedEncodable: unique symbol}
>;

/** @inheritdoc */
export class Reflected extends base.Struct implements ReflectedLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a Reflected from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a reflected struct from an array.
     *
     * @param array Array to decode from.
     * @returns Reflected instance.
     */
    public static decode(array: Uint8Array): Reflected {
        return new Reflected(array);
    }

    /**
     * Encode a reflected struct into an array.
     *
     * @param struct ReflectedEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ReflectedEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);
        let offset = 16;

        // Encode `header-length`
        array[0] = struct.headerLength;

        // Encode `reserved`
        array[1] = struct.reserved;

        // Encode `flags`
        view.setUint16(2, struct.flags, true);

        // Encode `reflected-id`
        view.setUint32(4, struct.reflectedId, true);

        // Encode `timestamp`
        view.setBigUint64(8, struct.timestamp, true);

        // Encode `envelope`
        offset += utils.encodeBytes(struct.envelope, array, offset);

        return array.subarray(0, offset);
    }

    /**
     * Get the amount of bytes that would be written when encoding a reflected struct into an
     * array.
     *
     * @param struct ReflectedEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ReflectedEncodable, 'byteLength'>,
    ): types.u53 {
        let offset = 16;
        offset += utils.getByteLength(struct.envelope);
        return offset;
    }

    /**
     * 'header-length' field accessor. See {@link ReflectedLike#headerLength} for the
     * field's description.
     */
    public get headerLength(): types.u8 {
        return utils.unwrap(this._array[0]);
    }

    /**
     * 'reserved' field accessor. See {@link ReflectedLike#reserved} for the
     * field's description.
     */
    public get reserved(): types.u8 {
        return utils.unwrap(this._array[1]);
    }

    /**
     * 'flags' field accessor. See {@link ReflectedLike#flags} for the
     * field's description.
     */
    public get flags(): types.u16 {
        return this._view.getUint16(2, true);
    }

    /**
     * 'reflected-id' field accessor. See {@link ReflectedLike#reflectedId} for the
     * field's description.
     */
    public get reflectedId(): types.u32 {
        return this._view.getUint32(4, true);
    }

    /**
     * 'timestamp' field accessor. See {@link ReflectedLike#timestamp} for the
     * field's description.
     */
    public get timestamp(): types.u64 {
        return this._view.getBigUint64(8, true);
    }

    /**
     * 'envelope' field accessor. See {@link ReflectedLike#envelope} for the
     * field's description.
     */
    public get envelope(): Uint8Array {
        return this._array.subarray(16);
    }

    /**
     * Create a snapshot of ReflectedLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ReflectedLike snapshot.
     */
    public snapshot(): ReflectedLike {
        return {
            headerLength: this.headerLength,
            reserved: this.reserved,
            flags: this.flags,
            reflectedId: this.reflectedId,
            timestamp: this.timestamp,
            envelope: this.envelope,
        };
    }

    /**
     * Create a clone of ReflectedLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ReflectedLike clone.
     */
    public clone(): Reflected {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new Reflected(array);
    }
}

/**
 * Acknowledges that a reflected message has been processed by the device.
 *
 * Direction: Client --> Server
 */
export interface ReflectedAckLike {
    /**
     * Should be set to all `0`s and ignored by the receiver.
     */
    readonly reserved: Uint8Array;

    /**
     * Refers to the `Reflected ID` as sent in the `Reflected` message.
     */
    readonly reflectId: types.u32;
}

/**
 * Encodable of {@link ReflectedAckLike}.
 */
interface ReflectedAckEncodable_ {
    /**
     * 'reserved' field value or encoder. See {@link ReflectedAckLike#reserved} for
     * the field's description.
     */
    readonly reserved: Uint8Array | types.ByteLengthEncoder;

    /**
     * 'reflect-id' field value or encoder. See {@link ReflectedAckLike#reflectId} for
     * the field's description.
     */
    readonly reflectId: types.u32;
}

/**
 * New-type for ReflectedAckEncodable.
 */
export type ReflectedAckEncodable = types.WeakOpaque<
    ReflectedAckEncodable_,
    {readonly ReflectedAckEncodable: unique symbol}
>;

/** @inheritdoc */
export class ReflectedAck extends base.Struct implements ReflectedAckLike {
    private readonly _array: Uint8Array;
    private readonly _view: DataView;

    /**
     * Create a ReflectedAck from an array for accessing properties.
     *
     * Note: When accessing, attributes will be decoded on-the-fly which may be expensive.
     */
    private constructor(array: Uint8Array) {
        super();
        this._array = array;
        this._view = new DataView(array.buffer, array.byteOffset, array.byteLength);
    }

    /**
     * Decode a reflected-ack struct from an array.
     *
     * @param array Array to decode from.
     * @returns ReflectedAck instance.
     */
    public static decode(array: Uint8Array): ReflectedAck {
        return new ReflectedAck(array);
    }

    /**
     * Encode a reflected-ack struct into an array.
     *
     * @param struct ReflectedAckEncodable to encode.
     * @param array Array to encode into.
     * @returns A subarray of array containing the encoded struct.
     */
    public static encode(
        struct: types.EncoderPick<ReflectedAckEncodable, 'encode'>,
        array: Uint8Array,
    ): Uint8Array {
        const view = new DataView(array.buffer, array.byteOffset, array.byteLength);

        // Encode `reserved`
        utils.encodeBytes(struct.reserved, array, 0);

        // Encode `reflect-id`
        view.setUint32(4, struct.reflectId, true);

        return array.subarray(0, 8);
    }

    /**
     * Get the amount of bytes that would be written when encoding a reflected-ack struct into an
     * array.
     *
     * @param struct ReflectedAckEncodable to encode.
     * @returns The amount of bytes that would be required to encode the struct.
     */
    public static byteLength(
        struct: types.EncoderPick<ReflectedAckEncodable, 'byteLength'>,
    ): types.u53 {
        return 8;
    }

    /**
     * 'reserved' field accessor. See {@link ReflectedAckLike#reserved} for the
     * field's description.
     */
    public get reserved(): Uint8Array {
        const offset = 0;
        return this._array.subarray(offset, offset + 4);
    }

    /**
     * 'reflect-id' field accessor. See {@link ReflectedAckLike#reflectId} for the
     * field's description.
     */
    public get reflectId(): types.u32 {
        return this._view.getUint32(4, true);
    }

    /**
     * Create a snapshot of ReflectedAckLike.
     *
     * Note: This is **not** a deep-copy, so byte arrays will still be views of the underlying
     *       buffer.
     *
     * @returns ReflectedAckLike snapshot.
     */
    public snapshot(): ReflectedAckLike {
        return {
            reserved: this.reserved,
            reflectId: this.reflectId,
        };
    }

    /**
     * Create a clone of ReflectedAckLike.
     *
     * Note: This is a deep-copy that will copy the underlying buffer.
     *
     * @returns ReflectedAckLike clone.
     */
    public clone(): ReflectedAck {
        const array = new Uint8Array(this._array.byteLength);
        array.set(this._array);
        return new ReflectedAck(array);
    }
}
