// automatically generated by the FlatBuffers compiler, do not modify

/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */

import * as flatbuffers from 'flatbuffers';

export class KeyValue implements flatbuffers.IUnpackableObject<KeyValueT> {
  bb: flatbuffers.ByteBuffer | null = null;
  bb_pos = 0;
  __init(i: number, bb: flatbuffers.ByteBuffer): KeyValue {
    this.bb_pos = i;
    this.bb = bb;
    return this;
  }

  static getRootAsKeyValue(
    bb: flatbuffers.ByteBuffer,
    obj?: KeyValue,
  ): KeyValue {
    return (obj || new KeyValue()).__init(
      bb.readInt32(bb.position()) + bb.position(),
      bb,
    );
  }

  static getSizePrefixedRootAsKeyValue(
    bb: flatbuffers.ByteBuffer,
    obj?: KeyValue,
  ): KeyValue {
    bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
    return (obj || new KeyValue()).__init(
      bb.readInt32(bb.position()) + bb.position(),
      bb,
    );
  }

  key(): string | null;
  key(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null;
  key(optionalEncoding?: any): string | Uint8Array | null {
    const offset = this.bb!.__offset(this.bb_pos, 4);
    return offset
      ? this.bb!.__string(this.bb_pos + offset, optionalEncoding)
      : null;
  }

  value(): string | null;
  value(optionalEncoding: flatbuffers.Encoding): string | Uint8Array | null;
  value(optionalEncoding?: any): string | Uint8Array | null {
    const offset = this.bb!.__offset(this.bb_pos, 6);
    return offset
      ? this.bb!.__string(this.bb_pos + offset, optionalEncoding)
      : null;
  }

  static getFullyQualifiedName(): string {
    return 'reflection.KeyValue';
  }

  static startKeyValue(builder: flatbuffers.Builder) {
    builder.startObject(2);
  }

  static addKey(builder: flatbuffers.Builder, keyOffset: flatbuffers.Offset) {
    builder.addFieldOffset(0, keyOffset, 0);
  }

  static addValue(
    builder: flatbuffers.Builder,
    valueOffset: flatbuffers.Offset,
  ) {
    builder.addFieldOffset(1, valueOffset, 0);
  }

  static endKeyValue(builder: flatbuffers.Builder): flatbuffers.Offset {
    const offset = builder.endObject();
    builder.requiredField(offset, 4); // key
    return offset;
  }

  static createKeyValue(
    builder: flatbuffers.Builder,
    keyOffset: flatbuffers.Offset,
    valueOffset: flatbuffers.Offset,
  ): flatbuffers.Offset {
    KeyValue.startKeyValue(builder);
    KeyValue.addKey(builder, keyOffset);
    KeyValue.addValue(builder, valueOffset);
    return KeyValue.endKeyValue(builder);
  }

  unpack(): KeyValueT {
    return new KeyValueT(this.key(), this.value());
  }

  unpackTo(_o: KeyValueT): void {
    _o.key = this.key();
    _o.value = this.value();
  }
}

export class KeyValueT implements flatbuffers.IGeneratedObject {
  constructor(
    public key: string | Uint8Array | null = null,
    public value: string | Uint8Array | null = null,
  ) {}

  pack(builder: flatbuffers.Builder): flatbuffers.Offset {
    const key = this.key !== null ? builder.createString(this.key!) : 0;
    const value = this.value !== null ? builder.createString(this.value!) : 0;

    return KeyValue.createKeyValue(builder, key, value);
  }
}
