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

import * as flatbuffers from 'flatbuffers';


export enum BaseType {
  None = 0,
  UType = 1,
  Bool = 2,
  Byte = 3,
  UByte = 4,
  Short = 5,
  UShort = 6,
  Int = 7,
  UInt = 8,
  Long = 9,
  ULong = 10,
  Float = 11,
  Double = 12,
  String = 13,
  Vector = 14,
  Obj = 15,
  Union = 16,
  Array = 17,
  MaxBaseType = 18
}

/**
 * New schema language features that are not supported by old code generators.
 */
export enum AdvancedFeatures {
  AdvancedArrayFeatures = '1',
  AdvancedUnionFeatures = '2',
  OptionalScalars = '4',
  DefaultVectorsAndStrings = '8'
}

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

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

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

baseType():BaseType {
  const offset = this.bb!.__offset(this.bb_pos, 4);
  return offset ? this.bb!.readInt8(this.bb_pos + offset) : BaseType.None;
}

mutate_base_type(value:BaseType):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 4);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, value);
  return true;
}

element():BaseType {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.readInt8(this.bb_pos + offset) : BaseType.None;
}

mutate_element(value:BaseType):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 6);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, value);
  return true;
}

index():number {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? this.bb!.readInt32(this.bb_pos + offset) : -1;
}

mutate_index(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 8);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt32(this.bb_pos + offset, value);
  return true;
}

fixedLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
}

mutate_fixed_length(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 10);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint16(this.bb_pos + offset, value);
  return true;
}

/**
 * The size (octets) of the `base_type` field.
 */
baseSize():number {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.readUint32(this.bb_pos + offset) : 4;
}

mutate_base_size(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 12);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint32(this.bb_pos + offset, value);
  return true;
}

/**
 * The size (octets) of the `element` field, if present.
 */
elementSize():number {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
}

mutate_element_size(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 14);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint32(this.bb_pos + offset, value);
  return true;
}

static getFullyQualifiedName():string {
  return 'reflection_Type';
}

static startType(builder:flatbuffers.Builder) {
  builder.startObject(6);
}

static addBaseType(builder:flatbuffers.Builder, baseType:BaseType) {
  builder.addFieldInt8(0, baseType, BaseType.None);
}

static addElement(builder:flatbuffers.Builder, element:BaseType) {
  builder.addFieldInt8(1, element, BaseType.None);
}

static addIndex(builder:flatbuffers.Builder, index:number) {
  builder.addFieldInt32(2, index, -1);
}

static addFixedLength(builder:flatbuffers.Builder, fixedLength:number) {
  builder.addFieldInt16(3, fixedLength, 0);
}

static addBaseSize(builder:flatbuffers.Builder, baseSize:number) {
  builder.addFieldInt32(4, baseSize, 4);
}

static addElementSize(builder:flatbuffers.Builder, elementSize:number) {
  builder.addFieldInt32(5, elementSize, 0);
}

static endType(builder:flatbuffers.Builder):flatbuffers.Offset {
  const offset = builder.endObject();
  return offset;
}

static createType(builder:flatbuffers.Builder, baseType:BaseType, element:BaseType, index:number, fixedLength:number, baseSize:number, elementSize:number):flatbuffers.Offset {
  Type.startType(builder);
  Type.addBaseType(builder, baseType);
  Type.addElement(builder, element);
  Type.addIndex(builder, index);
  Type.addFixedLength(builder, fixedLength);
  Type.addBaseSize(builder, baseSize);
  Type.addElementSize(builder, elementSize);
  return Type.endType(builder);
}

unpack(): TypeT {
  return new TypeT(
    this.baseType(),
    this.element(),
    this.index(),
    this.fixedLength(),
    this.baseSize(),
    this.elementSize()
  );
}


unpackTo(_o: TypeT): void {
  _o.baseType = this.baseType();
  _o.element = this.element();
  _o.index = this.index();
  _o.fixedLength = this.fixedLength();
  _o.baseSize = this.baseSize();
  _o.elementSize = this.elementSize();
}
}

export class TypeT implements flatbuffers.IGeneratedObject {
constructor(
  public baseType: BaseType = BaseType.None,
  public element: BaseType = BaseType.None,
  public index: number = -1,
  public fixedLength: number = 0,
  public baseSize: number = 4,
  public elementSize: number = 0
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  return Type.createType(builder,
    this.baseType,
    this.element,
    this.index,
    this.fixedLength,
    this.baseSize,
    this.elementSize
  );
}
}

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
  );
}
}

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

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

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

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(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():bigint {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}

mutate_value(value:bigint):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 6);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt64(this.bb_pos + offset, value);
  return true;
}

unionType(obj?:Type):Type|null {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? (obj || new Type()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}

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

documentationLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

attributes(index: number, obj?:KeyValue):KeyValue|null {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? (obj || new KeyValue()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

attributesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

static getFullyQualifiedName():string {
  return 'reflection_EnumVal';
}

static startEnumVal(builder:flatbuffers.Builder) {
  builder.startObject(6);
}

static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, nameOffset, 0);
}

static addValue(builder:flatbuffers.Builder, value:bigint) {
  builder.addFieldInt64(1, value, BigInt('0'));
}

static addUnionType(builder:flatbuffers.Builder, unionTypeOffset:flatbuffers.Offset) {
  builder.addFieldOffset(3, unionTypeOffset, 0);
}

static addDocumentation(builder:flatbuffers.Builder, documentationOffset:flatbuffers.Offset) {
  builder.addFieldOffset(4, documentationOffset, 0);
}

static createDocumentationVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startDocumentationVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addAttributes(builder:flatbuffers.Builder, attributesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(5, attributesOffset, 0);
}

static createAttributesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startAttributesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

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


unpack(): EnumValT {
  return new EnumValT(
    this.name(),
    this.value(),
    (this.unionType() !== null ? this.unionType()!.unpack() : null),
    this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength()),
    this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength())
  );
}


unpackTo(_o: EnumValT): void {
  _o.name = this.name();
  _o.value = this.value();
  _o.unionType = (this.unionType() !== null ? this.unionType()!.unpack() : null);
  _o.documentation = this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength());
  _o.attributes = this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength());
}
}

export class EnumValT implements flatbuffers.IGeneratedObject {
constructor(
  public name: string|Uint8Array|null = null,
  public value: bigint = BigInt('0'),
  public unionType: TypeT|null = null,
  public documentation: (string)[] = [],
  public attributes: (KeyValueT)[] = []
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const name = (this.name !== null ? builder.createString(this.name!) : 0);
  const unionType = (this.unionType !== null ? this.unionType!.pack(builder) : 0);
  const documentation = EnumVal.createDocumentationVector(builder, builder.createObjectOffsetList(this.documentation));
  const attributes = EnumVal.createAttributesVector(builder, builder.createObjectOffsetList(this.attributes));

  EnumVal.startEnumVal(builder);
  EnumVal.addName(builder, name);
  EnumVal.addValue(builder, this.value);
  EnumVal.addUnionType(builder, unionType);
  EnumVal.addDocumentation(builder, documentation);
  EnumVal.addAttributes(builder, attributes);

  return EnumVal.endEnumVal(builder);
}
}

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

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

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

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(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;
}

values(index: number, obj?:EnumVal):EnumVal|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? (obj || new EnumVal()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

valuesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

isUnion():boolean {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}

mutate_is_union(value:boolean):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 8);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, +value);
  return true;
}

underlyingType(obj?:Type):Type|null {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? (obj || new Type()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}

attributes(index: number, obj?:KeyValue):KeyValue|null {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? (obj || new KeyValue()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

attributesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

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

documentationLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

/**
 * File that this Enum is declared in.
 */
declarationFile():string|null
declarationFile(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
declarationFile(optionalEncoding?:any):string|Uint8Array|null {
  const offset = this.bb!.__offset(this.bb_pos, 16);
  return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}

static getFullyQualifiedName():string {
  return 'reflection_Enum';
}

static startEnum(builder:flatbuffers.Builder) {
  builder.startObject(7);
}

static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, nameOffset, 0);
}

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

static createValuesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startValuesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addIsUnion(builder:flatbuffers.Builder, isUnion:boolean) {
  builder.addFieldInt8(2, +isUnion, +false);
}

static addUnderlyingType(builder:flatbuffers.Builder, underlyingTypeOffset:flatbuffers.Offset) {
  builder.addFieldOffset(3, underlyingTypeOffset, 0);
}

static addAttributes(builder:flatbuffers.Builder, attributesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(4, attributesOffset, 0);
}

static createAttributesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startAttributesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDocumentation(builder:flatbuffers.Builder, documentationOffset:flatbuffers.Offset) {
  builder.addFieldOffset(5, documentationOffset, 0);
}

static createDocumentationVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startDocumentationVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDeclarationFile(builder:flatbuffers.Builder, declarationFileOffset:flatbuffers.Offset) {
  builder.addFieldOffset(6, declarationFileOffset, 0);
}

static endEnum(builder:flatbuffers.Builder):flatbuffers.Offset {
  const offset = builder.endObject();
  builder.requiredField(offset, 4) // name
  builder.requiredField(offset, 6) // values
  builder.requiredField(offset, 10) // underlying_type
  return offset;
}


unpack(): EnumT {
  return new EnumT(
    this.name(),
    this.bb!.createObjList<EnumVal, EnumValT>(this.values.bind(this), this.valuesLength()),
    this.isUnion(),
    (this.underlyingType() !== null ? this.underlyingType()!.unpack() : null),
    this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength()),
    this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength()),
    this.declarationFile()
  );
}


unpackTo(_o: EnumT): void {
  _o.name = this.name();
  _o.values = this.bb!.createObjList<EnumVal, EnumValT>(this.values.bind(this), this.valuesLength());
  _o.isUnion = this.isUnion();
  _o.underlyingType = (this.underlyingType() !== null ? this.underlyingType()!.unpack() : null);
  _o.attributes = this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength());
  _o.documentation = this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength());
  _o.declarationFile = this.declarationFile();
}
}

export class EnumT implements flatbuffers.IGeneratedObject {
constructor(
  public name: string|Uint8Array|null = null,
  public values: (EnumValT)[] = [],
  public isUnion: boolean = false,
  public underlyingType: TypeT|null = null,
  public attributes: (KeyValueT)[] = [],
  public documentation: (string)[] = [],
  public declarationFile: string|Uint8Array|null = null
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const name = (this.name !== null ? builder.createString(this.name!) : 0);
  const values = Enum.createValuesVector(builder, builder.createObjectOffsetList(this.values));
  const underlyingType = (this.underlyingType !== null ? this.underlyingType!.pack(builder) : 0);
  const attributes = Enum.createAttributesVector(builder, builder.createObjectOffsetList(this.attributes));
  const documentation = Enum.createDocumentationVector(builder, builder.createObjectOffsetList(this.documentation));
  const declarationFile = (this.declarationFile !== null ? builder.createString(this.declarationFile!) : 0);

  Enum.startEnum(builder);
  Enum.addName(builder, name);
  Enum.addValues(builder, values);
  Enum.addIsUnion(builder, this.isUnion);
  Enum.addUnderlyingType(builder, underlyingType);
  Enum.addAttributes(builder, attributes);
  Enum.addDocumentation(builder, documentation);
  Enum.addDeclarationFile(builder, declarationFile);

  return Enum.endEnum(builder);
}
}

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

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

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

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(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;
}

type(obj?:Type):Type|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? (obj || new Type()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}

id():number {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
}

mutate_id(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 8);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint16(this.bb_pos + offset, value);
  return true;
}

offset():number {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
}

mutate_offset(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 10);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint16(this.bb_pos + offset, value);
  return true;
}

defaultInteger():bigint {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}

mutate_default_integer(value:bigint):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 12);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt64(this.bb_pos + offset, value);
  return true;
}

defaultReal():number {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
}

mutate_default_real(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 14);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeFloat64(this.bb_pos + offset, value);
  return true;
}

deprecated():boolean {
  const offset = this.bb!.__offset(this.bb_pos, 16);
  return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}

mutate_deprecated(value:boolean):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 16);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, +value);
  return true;
}

required():boolean {
  const offset = this.bb!.__offset(this.bb_pos, 18);
  return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}

mutate_required(value:boolean):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 18);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, +value);
  return true;
}

key():boolean {
  const offset = this.bb!.__offset(this.bb_pos, 20);
  return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}

mutate_key(value:boolean):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 20);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, +value);
  return true;
}

attributes(index: number, obj?:KeyValue):KeyValue|null {
  const offset = this.bb!.__offset(this.bb_pos, 22);
  return offset ? (obj || new KeyValue()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

attributesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 22);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

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

documentationLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 24);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

optional():boolean {
  const offset = this.bb!.__offset(this.bb_pos, 26);
  return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}

mutate_optional(value:boolean):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 26);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, +value);
  return true;
}

/**
 * Number of padding octets to always add after this field. Structs only.
 */
padding():number {
  const offset = this.bb!.__offset(this.bb_pos, 28);
  return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
}

mutate_padding(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 28);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint16(this.bb_pos + offset, value);
  return true;
}

static getFullyQualifiedName():string {
  return 'reflection_Field';
}

static startField(builder:flatbuffers.Builder) {
  builder.startObject(13);
}

static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, nameOffset, 0);
}

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

static addId(builder:flatbuffers.Builder, id:number) {
  builder.addFieldInt16(2, id, 0);
}

static addOffset(builder:flatbuffers.Builder, offset:number) {
  builder.addFieldInt16(3, offset, 0);
}

static addDefaultInteger(builder:flatbuffers.Builder, defaultInteger:bigint) {
  builder.addFieldInt64(4, defaultInteger, BigInt('0'));
}

static addDefaultReal(builder:flatbuffers.Builder, defaultReal:number) {
  builder.addFieldFloat64(5, defaultReal, 0.0);
}

static addDeprecated(builder:flatbuffers.Builder, deprecated:boolean) {
  builder.addFieldInt8(6, +deprecated, +false);
}

static addRequired(builder:flatbuffers.Builder, required:boolean) {
  builder.addFieldInt8(7, +required, +false);
}

static addKey(builder:flatbuffers.Builder, key:boolean) {
  builder.addFieldInt8(8, +key, +false);
}

static addAttributes(builder:flatbuffers.Builder, attributesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(9, attributesOffset, 0);
}

static createAttributesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startAttributesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDocumentation(builder:flatbuffers.Builder, documentationOffset:flatbuffers.Offset) {
  builder.addFieldOffset(10, documentationOffset, 0);
}

static createDocumentationVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startDocumentationVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addOptional(builder:flatbuffers.Builder, optional:boolean) {
  builder.addFieldInt8(11, +optional, +false);
}

static addPadding(builder:flatbuffers.Builder, padding:number) {
  builder.addFieldInt16(12, padding, 0);
}

static endField(builder:flatbuffers.Builder):flatbuffers.Offset {
  const offset = builder.endObject();
  builder.requiredField(offset, 4) // name
  builder.requiredField(offset, 6) // type
  return offset;
}


unpack(): FieldT {
  return new FieldT(
    this.name(),
    (this.type() !== null ? this.type()!.unpack() : null),
    this.id(),
    this.offset(),
    this.defaultInteger(),
    this.defaultReal(),
    this.deprecated(),
    this.required(),
    this.key(),
    this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength()),
    this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength()),
    this.optional(),
    this.padding()
  );
}


unpackTo(_o: FieldT): void {
  _o.name = this.name();
  _o.type = (this.type() !== null ? this.type()!.unpack() : null);
  _o.id = this.id();
  _o.offset = this.offset();
  _o.defaultInteger = this.defaultInteger();
  _o.defaultReal = this.defaultReal();
  _o.deprecated = this.deprecated();
  _o.required = this.required();
  _o.key = this.key();
  _o.attributes = this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength());
  _o.documentation = this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength());
  _o.optional = this.optional();
  _o.padding = this.padding();
}
}

export class FieldT implements flatbuffers.IGeneratedObject {
constructor(
  public name: string|Uint8Array|null = null,
  public type: TypeT|null = null,
  public id: number = 0,
  public offset: number = 0,
  public defaultInteger: bigint = BigInt('0'),
  public defaultReal: number = 0.0,
  public deprecated: boolean = false,
  public required: boolean = false,
  public key: boolean = false,
  public attributes: (KeyValueT)[] = [],
  public documentation: (string)[] = [],
  public optional: boolean = false,
  public padding: number = 0
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const name = (this.name !== null ? builder.createString(this.name!) : 0);
  const type = (this.type !== null ? this.type!.pack(builder) : 0);
  const attributes = Field.createAttributesVector(builder, builder.createObjectOffsetList(this.attributes));
  const documentation = Field.createDocumentationVector(builder, builder.createObjectOffsetList(this.documentation));

  Field.startField(builder);
  Field.addName(builder, name);
  Field.addType(builder, type);
  Field.addId(builder, this.id);
  Field.addOffset(builder, this.offset);
  Field.addDefaultInteger(builder, this.defaultInteger);
  Field.addDefaultReal(builder, this.defaultReal);
  Field.addDeprecated(builder, this.deprecated);
  Field.addRequired(builder, this.required);
  Field.addKey(builder, this.key);
  Field.addAttributes(builder, attributes);
  Field.addDocumentation(builder, documentation);
  Field.addOptional(builder, this.optional);
  Field.addPadding(builder, this.padding);

  return Field.endField(builder);
}
}

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

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

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

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(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;
}

fields(index: number, obj?:Field):Field|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? (obj || new Field()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

fieldsLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

isStruct():boolean {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}

mutate_is_struct(value:boolean):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 8);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt8(this.bb_pos + offset, +value);
  return true;
}

minalign():number {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}

mutate_minalign(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 10);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt32(this.bb_pos + offset, value);
  return true;
}

bytesize():number {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}

mutate_bytesize(value:number):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 12);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeInt32(this.bb_pos + offset, value);
  return true;
}

attributes(index: number, obj?:KeyValue):KeyValue|null {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? (obj || new KeyValue()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

attributesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

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

documentationLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 16);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

/**
 * File that this Object is declared in.
 */
declarationFile():string|null
declarationFile(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
declarationFile(optionalEncoding?:any):string|Uint8Array|null {
  const offset = this.bb!.__offset(this.bb_pos, 18);
  return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}

static getFullyQualifiedName():string {
  return 'reflection_Object';
}

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

static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, nameOffset, 0);
}

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

static createFieldsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startFieldsVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addIsStruct(builder:flatbuffers.Builder, isStruct:boolean) {
  builder.addFieldInt8(2, +isStruct, +false);
}

static addMinalign(builder:flatbuffers.Builder, minalign:number) {
  builder.addFieldInt32(3, minalign, 0);
}

static addBytesize(builder:flatbuffers.Builder, bytesize:number) {
  builder.addFieldInt32(4, bytesize, 0);
}

static addAttributes(builder:flatbuffers.Builder, attributesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(5, attributesOffset, 0);
}

static createAttributesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startAttributesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDocumentation(builder:flatbuffers.Builder, documentationOffset:flatbuffers.Offset) {
  builder.addFieldOffset(6, documentationOffset, 0);
}

static createDocumentationVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startDocumentationVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDeclarationFile(builder:flatbuffers.Builder, declarationFileOffset:flatbuffers.Offset) {
  builder.addFieldOffset(7, declarationFileOffset, 0);
}

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

static createObject(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, fieldsOffset:flatbuffers.Offset, isStruct:boolean, minalign:number, bytesize:number, attributesOffset:flatbuffers.Offset, documentationOffset:flatbuffers.Offset, declarationFileOffset:flatbuffers.Offset):flatbuffers.Offset {
  Object_.startObject(builder);
  Object_.addName(builder, nameOffset);
  Object_.addFields(builder, fieldsOffset);
  Object_.addIsStruct(builder, isStruct);
  Object_.addMinalign(builder, minalign);
  Object_.addBytesize(builder, bytesize);
  Object_.addAttributes(builder, attributesOffset);
  Object_.addDocumentation(builder, documentationOffset);
  Object_.addDeclarationFile(builder, declarationFileOffset);
  return Object_.endObject(builder);
}

unpack(): Object_T {
  return new Object_T(
    this.name(),
    this.bb!.createObjList<Field, FieldT>(this.fields.bind(this), this.fieldsLength()),
    this.isStruct(),
    this.minalign(),
    this.bytesize(),
    this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength()),
    this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength()),
    this.declarationFile()
  );
}


unpackTo(_o: Object_T): void {
  _o.name = this.name();
  _o.fields = this.bb!.createObjList<Field, FieldT>(this.fields.bind(this), this.fieldsLength());
  _o.isStruct = this.isStruct();
  _o.minalign = this.minalign();
  _o.bytesize = this.bytesize();
  _o.attributes = this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength());
  _o.documentation = this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength());
  _o.declarationFile = this.declarationFile();
}
}

export class Object_T implements flatbuffers.IGeneratedObject {
constructor(
  public name: string|Uint8Array|null = null,
  public fields: (FieldT)[] = [],
  public isStruct: boolean = false,
  public minalign: number = 0,
  public bytesize: number = 0,
  public attributes: (KeyValueT)[] = [],
  public documentation: (string)[] = [],
  public declarationFile: string|Uint8Array|null = null
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const name = (this.name !== null ? builder.createString(this.name!) : 0);
  const fields = Object_.createFieldsVector(builder, builder.createObjectOffsetList(this.fields));
  const attributes = Object_.createAttributesVector(builder, builder.createObjectOffsetList(this.attributes));
  const documentation = Object_.createDocumentationVector(builder, builder.createObjectOffsetList(this.documentation));
  const declarationFile = (this.declarationFile !== null ? builder.createString(this.declarationFile!) : 0);

  return Object_.createObject(builder,
    name,
    fields,
    this.isStruct,
    this.minalign,
    this.bytesize,
    attributes,
    documentation,
    declarationFile
  );
}
}

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

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

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

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(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;
}

request(obj?:Object_):Object_|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? (obj || new Object_()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}

response(obj?:Object_):Object_|null {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? (obj || new Object_()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}

attributes(index: number, obj?:KeyValue):KeyValue|null {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? (obj || new KeyValue()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

attributesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

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

documentationLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

static getFullyQualifiedName():string {
  return 'reflection_RPCCall';
}

static startRPCCall(builder:flatbuffers.Builder) {
  builder.startObject(5);
}

static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, nameOffset, 0);
}

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

static addResponse(builder:flatbuffers.Builder, responseOffset:flatbuffers.Offset) {
  builder.addFieldOffset(2, responseOffset, 0);
}

static addAttributes(builder:flatbuffers.Builder, attributesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(3, attributesOffset, 0);
}

static createAttributesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startAttributesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDocumentation(builder:flatbuffers.Builder, documentationOffset:flatbuffers.Offset) {
  builder.addFieldOffset(4, documentationOffset, 0);
}

static createDocumentationVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startDocumentationVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static endRPCCall(builder:flatbuffers.Builder):flatbuffers.Offset {
  const offset = builder.endObject();
  builder.requiredField(offset, 4) // name
  builder.requiredField(offset, 6) // request
  builder.requiredField(offset, 8) // response
  return offset;
}


unpack(): RPCCallT {
  return new RPCCallT(
    this.name(),
    (this.request() !== null ? this.request()!.unpack() : null),
    (this.response() !== null ? this.response()!.unpack() : null),
    this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength()),
    this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength())
  );
}


unpackTo(_o: RPCCallT): void {
  _o.name = this.name();
  _o.request = (this.request() !== null ? this.request()!.unpack() : null);
  _o.response = (this.response() !== null ? this.response()!.unpack() : null);
  _o.attributes = this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength());
  _o.documentation = this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength());
}
}

export class RPCCallT implements flatbuffers.IGeneratedObject {
constructor(
  public name: string|Uint8Array|null = null,
  public request: Object_T|null = null,
  public response: Object_T|null = null,
  public attributes: (KeyValueT)[] = [],
  public documentation: (string)[] = []
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const name = (this.name !== null ? builder.createString(this.name!) : 0);
  const request = (this.request !== null ? this.request!.pack(builder) : 0);
  const response = (this.response !== null ? this.response!.pack(builder) : 0);
  const attributes = RPCCall.createAttributesVector(builder, builder.createObjectOffsetList(this.attributes));
  const documentation = RPCCall.createDocumentationVector(builder, builder.createObjectOffsetList(this.documentation));

  RPCCall.startRPCCall(builder);
  RPCCall.addName(builder, name);
  RPCCall.addRequest(builder, request);
  RPCCall.addResponse(builder, response);
  RPCCall.addAttributes(builder, attributes);
  RPCCall.addDocumentation(builder, documentation);

  return RPCCall.endRPCCall(builder);
}
}

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

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

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

name():string|null
name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
name(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;
}

calls(index: number, obj?:RPCCall):RPCCall|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? (obj || new RPCCall()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

callsLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

attributes(index: number, obj?:KeyValue):KeyValue|null {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? (obj || new KeyValue()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

attributesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 8);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

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

documentationLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 10);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

/**
 * File that this Service is declared in.
 */
declarationFile():string|null
declarationFile(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
declarationFile(optionalEncoding?:any):string|Uint8Array|null {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}

static getFullyQualifiedName():string {
  return 'reflection_Service';
}

static startService(builder:flatbuffers.Builder) {
  builder.startObject(5);
}

static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, nameOffset, 0);
}

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

static createCallsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startCallsVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addAttributes(builder:flatbuffers.Builder, attributesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(2, attributesOffset, 0);
}

static createAttributesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startAttributesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDocumentation(builder:flatbuffers.Builder, documentationOffset:flatbuffers.Offset) {
  builder.addFieldOffset(3, documentationOffset, 0);
}

static createDocumentationVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startDocumentationVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addDeclarationFile(builder:flatbuffers.Builder, declarationFileOffset:flatbuffers.Offset) {
  builder.addFieldOffset(4, declarationFileOffset, 0);
}

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

static createService(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset, callsOffset:flatbuffers.Offset, attributesOffset:flatbuffers.Offset, documentationOffset:flatbuffers.Offset, declarationFileOffset:flatbuffers.Offset):flatbuffers.Offset {
  Service.startService(builder);
  Service.addName(builder, nameOffset);
  Service.addCalls(builder, callsOffset);
  Service.addAttributes(builder, attributesOffset);
  Service.addDocumentation(builder, documentationOffset);
  Service.addDeclarationFile(builder, declarationFileOffset);
  return Service.endService(builder);
}

unpack(): ServiceT {
  return new ServiceT(
    this.name(),
    this.bb!.createObjList<RPCCall, RPCCallT>(this.calls.bind(this), this.callsLength()),
    this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength()),
    this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength()),
    this.declarationFile()
  );
}


unpackTo(_o: ServiceT): void {
  _o.name = this.name();
  _o.calls = this.bb!.createObjList<RPCCall, RPCCallT>(this.calls.bind(this), this.callsLength());
  _o.attributes = this.bb!.createObjList<KeyValue, KeyValueT>(this.attributes.bind(this), this.attributesLength());
  _o.documentation = this.bb!.createScalarList<string>(this.documentation.bind(this), this.documentationLength());
  _o.declarationFile = this.declarationFile();
}
}

export class ServiceT implements flatbuffers.IGeneratedObject {
constructor(
  public name: string|Uint8Array|null = null,
  public calls: (RPCCallT)[] = [],
  public attributes: (KeyValueT)[] = [],
  public documentation: (string)[] = [],
  public declarationFile: string|Uint8Array|null = null
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const name = (this.name !== null ? builder.createString(this.name!) : 0);
  const calls = Service.createCallsVector(builder, builder.createObjectOffsetList(this.calls));
  const attributes = Service.createAttributesVector(builder, builder.createObjectOffsetList(this.attributes));
  const documentation = Service.createDocumentationVector(builder, builder.createObjectOffsetList(this.documentation));
  const declarationFile = (this.declarationFile !== null ? builder.createString(this.declarationFile!) : 0);

  return Service.createService(builder,
    name,
    calls,
    attributes,
    documentation,
    declarationFile
  );
}
}

/**
 * File specific information.
 * Symbols declared within a file may be recovered by iterating over all
 * symbols and examining the `declaration_file` field.
 */
export class SchemaFile implements flatbuffers.IUnpackableObject<SchemaFileT> {
  bb: flatbuffers.ByteBuffer|null = null;
  bb_pos = 0;
  __init(i:number, bb:flatbuffers.ByteBuffer):SchemaFile {
  this.bb_pos = i;
  this.bb = bb;
  return this;
}

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

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

/**
 * Filename, relative to project root.
 */
filename():string|null
filename(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
filename(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;
}

/**
 * Names of included files, relative to project root.
 */
includedFilenames(index: number):string
includedFilenames(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
includedFilenames(index: number,optionalEncoding?:any):string|Uint8Array|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
}

includedFilenamesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

static getFullyQualifiedName():string {
  return 'reflection_SchemaFile';
}

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

static addFilename(builder:flatbuffers.Builder, filenameOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, filenameOffset, 0);
}

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

static createIncludedFilenamesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startIncludedFilenamesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

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

static createSchemaFile(builder:flatbuffers.Builder, filenameOffset:flatbuffers.Offset, includedFilenamesOffset:flatbuffers.Offset):flatbuffers.Offset {
  SchemaFile.startSchemaFile(builder);
  SchemaFile.addFilename(builder, filenameOffset);
  SchemaFile.addIncludedFilenames(builder, includedFilenamesOffset);
  return SchemaFile.endSchemaFile(builder);
}

unpack(): SchemaFileT {
  return new SchemaFileT(
    this.filename(),
    this.bb!.createScalarList<string>(this.includedFilenames.bind(this), this.includedFilenamesLength())
  );
}


unpackTo(_o: SchemaFileT): void {
  _o.filename = this.filename();
  _o.includedFilenames = this.bb!.createScalarList<string>(this.includedFilenames.bind(this), this.includedFilenamesLength());
}
}

export class SchemaFileT implements flatbuffers.IGeneratedObject {
constructor(
  public filename: string|Uint8Array|null = null,
  public includedFilenames: (string)[] = []
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const filename = (this.filename !== null ? builder.createString(this.filename!) : 0);
  const includedFilenames = SchemaFile.createIncludedFilenamesVector(builder, builder.createObjectOffsetList(this.includedFilenames));

  return SchemaFile.createSchemaFile(builder,
    filename,
    includedFilenames
  );
}
}

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

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

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

static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {
  return bb.__has_identifier('BFBS');
}

objects(index: number, obj?:Object_):Object_|null {
  const offset = this.bb!.__offset(this.bb_pos, 4);
  return offset ? (obj || new Object_()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

objectsLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 4);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

enums(index: number, obj?:Enum):Enum|null {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? (obj || new Enum()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

enumsLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 6);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

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

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

rootTable(obj?:Object_):Object_|null {
  const offset = this.bb!.__offset(this.bb_pos, 12);
  return offset ? (obj || new Object_()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}

services(index: number, obj?:Service):Service|null {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? (obj || new Service()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

servicesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 14);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

advancedFeatures():bigint {
  const offset = this.bb!.__offset(this.bb_pos, 16);
  return offset ? this.bb!.readUint64(this.bb_pos + offset) : BigInt('0');
}

mutate_advanced_features(value:bigint):boolean {
  const offset = this.bb!.__offset(this.bb_pos, 16);

  if (offset === 0) {
    return false;
  }

  this.bb!.writeUint64(this.bb_pos + offset, value);
  return true;
}

/**
 * All the files used in this compilation. Files are relative to where
 * flatc was invoked.
 */
fbsFiles(index: number, obj?:SchemaFile):SchemaFile|null {
  const offset = this.bb!.__offset(this.bb_pos, 18);
  return offset ? (obj || new SchemaFile()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}

fbsFilesLength():number {
  const offset = this.bb!.__offset(this.bb_pos, 18);
  return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}

static getFullyQualifiedName():string {
  return 'reflection_Schema';
}

static startSchema(builder:flatbuffers.Builder) {
  builder.startObject(8);
}

static addObjects(builder:flatbuffers.Builder, objectsOffset:flatbuffers.Offset) {
  builder.addFieldOffset(0, objectsOffset, 0);
}

static createObjectsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startObjectsVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

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

static createEnumsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startEnumsVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addFileIdent(builder:flatbuffers.Builder, fileIdentOffset:flatbuffers.Offset) {
  builder.addFieldOffset(2, fileIdentOffset, 0);
}

static addFileExt(builder:flatbuffers.Builder, fileExtOffset:flatbuffers.Offset) {
  builder.addFieldOffset(3, fileExtOffset, 0);
}

static addRootTable(builder:flatbuffers.Builder, rootTableOffset:flatbuffers.Offset) {
  builder.addFieldOffset(4, rootTableOffset, 0);
}

static addServices(builder:flatbuffers.Builder, servicesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(5, servicesOffset, 0);
}

static createServicesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startServicesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static addAdvancedFeatures(builder:flatbuffers.Builder, advancedFeatures:bigint) {
  builder.addFieldInt64(6, advancedFeatures, BigInt('0'));
}

static addFbsFiles(builder:flatbuffers.Builder, fbsFilesOffset:flatbuffers.Offset) {
  builder.addFieldOffset(7, fbsFilesOffset, 0);
}

static createFbsFilesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
  builder.startVector(4, data.length, 4);
  for (let i = data.length - 1; i >= 0; i--) {
    builder.addOffset(data[i]!);
  }
  return builder.endVector();
}

static startFbsFilesVector(builder:flatbuffers.Builder, numElems:number) {
  builder.startVector(4, numElems, 4);
}

static endSchema(builder:flatbuffers.Builder):flatbuffers.Offset {
  const offset = builder.endObject();
  builder.requiredField(offset, 4) // objects
  builder.requiredField(offset, 6) // enums
  return offset;
}

static finishSchemaBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
  builder.finish(offset, 'BFBS');
}

static finishSizePrefixedSchemaBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
  builder.finish(offset, 'BFBS', true);
}


unpack(): SchemaT {
  return new SchemaT(
    this.bb!.createObjList<Object_, Object_T>(this.objects.bind(this), this.objectsLength()),
    this.bb!.createObjList<Enum, EnumT>(this.enums.bind(this), this.enumsLength()),
    this.fileIdent(),
    this.fileExt(),
    (this.rootTable() !== null ? this.rootTable()!.unpack() : null),
    this.bb!.createObjList<Service, ServiceT>(this.services.bind(this), this.servicesLength()),
    this.advancedFeatures(),
    this.bb!.createObjList<SchemaFile, SchemaFileT>(this.fbsFiles.bind(this), this.fbsFilesLength())
  );
}


unpackTo(_o: SchemaT): void {
  _o.objects = this.bb!.createObjList<Object_, Object_T>(this.objects.bind(this), this.objectsLength());
  _o.enums = this.bb!.createObjList<Enum, EnumT>(this.enums.bind(this), this.enumsLength());
  _o.fileIdent = this.fileIdent();
  _o.fileExt = this.fileExt();
  _o.rootTable = (this.rootTable() !== null ? this.rootTable()!.unpack() : null);
  _o.services = this.bb!.createObjList<Service, ServiceT>(this.services.bind(this), this.servicesLength());
  _o.advancedFeatures = this.advancedFeatures();
  _o.fbsFiles = this.bb!.createObjList<SchemaFile, SchemaFileT>(this.fbsFiles.bind(this), this.fbsFilesLength());
}
}

export class SchemaT implements flatbuffers.IGeneratedObject {
constructor(
  public objects: (Object_T)[] = [],
  public enums: (EnumT)[] = [],
  public fileIdent: string|Uint8Array|null = null,
  public fileExt: string|Uint8Array|null = null,
  public rootTable: Object_T|null = null,
  public services: (ServiceT)[] = [],
  public advancedFeatures: bigint = BigInt('0'),
  public fbsFiles: (SchemaFileT)[] = []
){}


pack(builder:flatbuffers.Builder): flatbuffers.Offset {
  const objects = Schema.createObjectsVector(builder, builder.createObjectOffsetList(this.objects));
  const enums = Schema.createEnumsVector(builder, builder.createObjectOffsetList(this.enums));
  const fileIdent = (this.fileIdent !== null ? builder.createString(this.fileIdent!) : 0);
  const fileExt = (this.fileExt !== null ? builder.createString(this.fileExt!) : 0);
  const rootTable = (this.rootTable !== null ? this.rootTable!.pack(builder) : 0);
  const services = Schema.createServicesVector(builder, builder.createObjectOffsetList(this.services));
  const fbsFiles = Schema.createFbsFilesVector(builder, builder.createObjectOffsetList(this.fbsFiles));

  Schema.startSchema(builder);
  Schema.addObjects(builder, objects);
  Schema.addEnums(builder, enums);
  Schema.addFileIdent(builder, fileIdent);
  Schema.addFileExt(builder, fileExt);
  Schema.addRootTable(builder, rootTable);
  Schema.addServices(builder, services);
  Schema.addAdvancedFeatures(builder, this.advancedFeatures);
  Schema.addFbsFiles(builder, fbsFiles);

  return Schema.endSchema(builder);
}
}

