// automatically generated by the FlatBuffers compiler, do not modify
// swiftlint:disable all
// swiftformat:disable all

import FlatBuffers

public enum Color: UInt8, Enum, Verifiable {
  public typealias T = UInt8
  public static var byteSize: Int { return MemoryLayout<UInt8>.size }
  public var value: UInt8 { return self.rawValue }
  case red = 1
  ///  \brief color Green
  ///  Green is bit_flag with value (1u << 1)
  case green = 2
  ///  \brief color Blue (1u << 3)
  case blue = 8

  public static var max: Color { return .blue }
  public static var min: Color { return .red }
}

extension Color: Encodable {
  public func encode(to encoder: Encoder) throws {
    var container = encoder.singleValueContainer()
    switch self {
    case .red: try container.encode("Red")
    case .green: try container.encode("Green")
    case .blue: try container.encode("Blue")
    }
  }
}

public struct Test: NativeStruct, Verifiable, FlatbuffersInitializable {

  static func validateVersion() { FlatBuffersVersion_24_3_25() }

  private var _a: Int16
  private var _b: Int8
  private let padding0__: UInt8 = 0

  public init(_ bb: ByteBuffer, o: Int32) {
    let _accessor = Struct(bb: bb, position: o)
    _a = _accessor.readBuffer(of: Int16.self, at: 0)
    _b = _accessor.readBuffer(of: Int8.self, at: 2)
  }

  public init(a: Int16, b: Int8) {
    _a = a
    _b = b
  }

  public init() {
    _a = 0
    _b = 0
  }

  public var a: Int16 { _a }
  public var b: Int8 { _b }

  public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
    try verifier.inBuffer(position: position, of: Test.self)
  }
}

extension Test: Encodable {

  enum CodingKeys: String, CodingKey {
    case a = "a"
    case b = "b"
  }
  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    if a != 0 {
      try container.encodeIfPresent(a, forKey: .a)
    }
    if b != 0 {
      try container.encodeIfPresent(b, forKey: .b)
    }
  }
}

public struct Test_Mutable: FlatBufferObject {

  static func validateVersion() { FlatBuffersVersion_24_3_25() }
  public var __buffer: ByteBuffer! { return _accessor.bb }
  private var _accessor: Struct

  public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }

  public var a: Int16 { return _accessor.readBuffer(of: Int16.self, at: 0) }
  public var b: Int8 { return _accessor.readBuffer(of: Int8.self, at: 2) }
}

public struct Vec3: NativeStruct, Verifiable, FlatbuffersInitializable {

  static func validateVersion() { FlatBuffersVersion_24_3_25() }

  private var _x: Float32
  private var _y: Float32
  private var _z: Float32
  private let padding0__: UInt32 = 0
  private var _test1: Double
  private var _test2: UInt8
  private let padding1__: UInt8 = 0
  private var _test3: Test
  private let padding2__: UInt16 = 0

  public init(_ bb: ByteBuffer, o: Int32) {
    let _accessor = Struct(bb: bb, position: o)
    _x = _accessor.readBuffer(of: Float32.self, at: 0)
    _y = _accessor.readBuffer(of: Float32.self, at: 4)
    _z = _accessor.readBuffer(of: Float32.self, at: 8)
    _test1 = _accessor.readBuffer(of: Double.self, at: 16)
    _test2 = _accessor.readBuffer(of: UInt8.self, at: 24)
    _test3 = Test(_accessor.bb, o: _accessor.postion + 26)
  }

  public init(x: Float32, y: Float32, z: Float32, test1: Double, test2: Color, test3: Test) {
    _x = x
    _y = y
    _z = z
    _test1 = test1
    _test2 = test2.value
    _test3 = test3
  }

  public init() {
    _x = 0.0
    _y = 0.0
    _z = 0.0
    _test1 = 0.0
    _test2 = 0
    _test3 = Test()
  }

  public var x: Float32 { _x }
  public var y: Float32 { _y }
  public var z: Float32 { _z }
  public var test1: Double { _test1 }
  public var test2: Color { Color(rawValue: _test2)! }
  public var test3: Test { _test3 }

  public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
    try verifier.inBuffer(position: position, of: Vec3.self)
  }
}

extension Vec3: Encodable {

  enum CodingKeys: String, CodingKey {
    case x = "x"
    case y = "y"
    case z = "z"
    case test1 = "test1"
    case test2 = "test2"
    case test3 = "test3"
  }
  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    if x != 0.0 {
      try container.encodeIfPresent(x, forKey: .x)
    }
    if y != 0.0 {
      try container.encodeIfPresent(y, forKey: .y)
    }
    if z != 0.0 {
      try container.encodeIfPresent(z, forKey: .z)
    }
    if test1 != 0.0 {
      try container.encodeIfPresent(test1, forKey: .test1)
    }
    if test2 != .red {
      try container.encodeIfPresent(test2, forKey: .test2)
    }
    try container.encodeIfPresent(test3, forKey: .test3)
  }
}

public struct Vec3_Mutable: FlatBufferObject {

  static func validateVersion() { FlatBuffersVersion_24_3_25() }
  public var __buffer: ByteBuffer! { return _accessor.bb }
  private var _accessor: Struct

  public init(_ bb: ByteBuffer, o: Int32) { _accessor = Struct(bb: bb, position: o) }

  public var x: Float32 { return _accessor.readBuffer(of: Float32.self, at: 0) }
  public var y: Float32 { return _accessor.readBuffer(of: Float32.self, at: 4) }
  public var z: Float32 { return _accessor.readBuffer(of: Float32.self, at: 8) }
  public var test1: Double { return _accessor.readBuffer(of: Double.self, at: 16) }
  public var test2: Color { return Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: 24)) ?? .red }
  public var test3: Test_Mutable { return Test_Mutable(_accessor.bb, o: _accessor.postion + 26) }
}

///  an example documentation comment: "monster object"
public struct Monster: FlatBufferObject, Verifiable {

  static func validateVersion() { FlatBuffersVersion_24_3_25() }
  public var __buffer: ByteBuffer! { return _accessor.bb }
  private var _accessor: Table

  public static func getRootAsMonster(bb: ByteBuffer) -> Monster { return Monster(Table(bb: bb, position: Int32(bb.read(def: UOffset.self, position: bb.reader)) + Int32(bb.reader))) }

  private init(_ t: Table) { _accessor = t }
  public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }

  private enum VTOFFSET: VOffset {
    case pos = 4
    case mana = 6
    case hp = 8
    case name = 10
    case testarrayoftables = 12
    case inventory = 14
    case color = 16
    var v: Int32 { Int32(self.rawValue) }
    var p: VOffset { self.rawValue }
  }

  public var pos: Vec3? { let o = _accessor.offset(VTOFFSET.pos.v); return o == 0 ? nil : _accessor.readBuffer(of: Vec3.self, at: o) }
  public var mutablePos: Vec3_Mutable? { let o = _accessor.offset(VTOFFSET.pos.v); return o == 0 ? nil : Vec3_Mutable(_accessor.bb, o: o + _accessor.postion) }
  public var mana: Int16 { let o = _accessor.offset(VTOFFSET.mana.v); return o == 0 ? 150 : _accessor.readBuffer(of: Int16.self, at: o) }
  public var hp: Int16 { let o = _accessor.offset(VTOFFSET.hp.v); return o == 0 ? 100 : _accessor.readBuffer(of: Int16.self, at: o) }
  public var name: String! { let o = _accessor.offset(VTOFFSET.name.v); return _accessor.string(at: o) }
  public var nameSegmentArray: [UInt8]! { return _accessor.getVector(at: VTOFFSET.name.v) }
  public var hasTestarrayoftables: Bool { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? false : true }
  public var testarrayoftablesCount: Int32 { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? 0 : _accessor.vector(count: o) }
  public func testarrayoftables(at index: Int32) -> Monster? { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? nil : Monster(_accessor.bb, o: _accessor.indirect(_accessor.vector(at: o) + index * 4)) }
  public func testarrayoftablesBy(key: String) -> Monster? { let o = _accessor.offset(VTOFFSET.testarrayoftables.v); return o == 0 ? nil : Monster.lookupByKey(vector: _accessor.vector(at: o), key: key, fbb: _accessor.bb) }
  public var hasInventory: Bool { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? false : true }
  public var inventoryCount: Int32 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.vector(count: o) }
  public func inventory(at index: Int32) -> UInt8 { let o = _accessor.offset(VTOFFSET.inventory.v); return o == 0 ? 0 : _accessor.directRead(of: UInt8.self, offset: _accessor.vector(at: o) + index * 1) }
  public var inventory: [UInt8] { return _accessor.getVector(at: VTOFFSET.inventory.v) ?? [] }
  public var color: Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : Color(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .blue }
  public static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 7) }
  public static func add(pos: Vec3?, _ fbb: inout FlatBufferBuilder) { guard let pos = pos else { return }; fbb.create(struct: pos, position: VTOFFSET.pos.p) }
  public static func add(mana: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: mana, def: 150, at: VTOFFSET.mana.p) }
  public static func add(hp: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: hp, def: 100, at: VTOFFSET.hp.p) }
  public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VTOFFSET.name.p) }
  public static func addVectorOf(testarrayoftables: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: testarrayoftables, at: VTOFFSET.testarrayoftables.p) }
  public static func addVectorOf(inventory: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: inventory, at: VTOFFSET.inventory.p) }
  public static func add(color: Color, _ fbb: inout FlatBufferBuilder) { fbb.add(element: color.rawValue, def: 8, at: VTOFFSET.color.p) }
  public static func endMonster(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); fbb.require(table: end, fields: [10]); return end }
  public static func createMonster(
    _ fbb: inout FlatBufferBuilder,
    pos: Vec3? = nil,
    mana: Int16 = 150,
    hp: Int16 = 100,
    nameOffset name: Offset,
    testarrayoftablesVectorOffset testarrayoftables: Offset = Offset(),
    inventoryVectorOffset inventory: Offset = Offset(),
    color: Color = .blue
  ) -> Offset {
    let __start = Monster.startMonster(&fbb)
    Monster.add(pos: pos, &fbb)
    Monster.add(mana: mana, &fbb)
    Monster.add(hp: hp, &fbb)
    Monster.add(name: name, &fbb)
    Monster.addVectorOf(testarrayoftables: testarrayoftables, &fbb)
    Monster.addVectorOf(inventory: inventory, &fbb)
    Monster.add(color: color, &fbb)
    return Monster.endMonster(&fbb, start: __start)
  }
  public static func sortVectorOfMonster(offsets:[Offset], _ fbb: inout FlatBufferBuilder) -> Offset {
    var off = offsets
    off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: 10, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: 10, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } 
    return fbb.createVector(ofOffsets: off)
  }
  fileprivate static func lookupByKey(vector: Int32, key: String, fbb: ByteBuffer) -> Monster? {
    let key = key.utf8.map { $0 }
    var span = fbb.read(def: Int32.self, position: Int(vector - 4))
    var start: Int32 = 0
    while span != 0 {
      var middle = span / 2
      let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)
      let comp = Table.compare(Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: 10, fbb: fbb), key, fbb: fbb)
      if comp > 0 {
        span = middle
      } else if comp < 0 {
        middle += 1
        start += middle
        span -= middle
      } else {
        return Monster(fbb, o: tableOffset)
      }
    }
    return nil
  }

  public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
    var _v = try verifier.visitTable(at: position)
    try _v.visit(field: VTOFFSET.pos.p, fieldName: "pos", required: false, type: Vec3.self)
    try _v.visit(field: VTOFFSET.mana.p, fieldName: "mana", required: false, type: Int16.self)
    try _v.visit(field: VTOFFSET.hp.p, fieldName: "hp", required: false, type: Int16.self)
    try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: true, type: ForwardOffset<String>.self)
    try _v.visit(field: VTOFFSET.testarrayoftables.p, fieldName: "testarrayoftables", required: false, type: ForwardOffset<Vector<ForwardOffset<Monster>, Monster>>.self)
    try _v.visit(field: VTOFFSET.inventory.p, fieldName: "inventory", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self)
    try _v.visit(field: VTOFFSET.color.p, fieldName: "color", required: false, type: Color.self)
    _v.finish()
  }
}

extension Monster: Encodable {

  enum CodingKeys: String, CodingKey {
    case pos = "pos"
    case mana = "mana"
    case hp = "hp"
    case name = "name"
    case testarrayoftables = "testarrayoftables"
    case inventory = "inventory"
    case color = "color"
  }
  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encodeIfPresent(pos, forKey: .pos)
    if mana != 150 {
      try container.encodeIfPresent(mana, forKey: .mana)
    }
    if hp != 100 {
      try container.encodeIfPresent(hp, forKey: .hp)
    }
    try container.encodeIfPresent(name, forKey: .name)
    if testarrayoftablesCount > 0 {
      var contentEncoder = container.nestedUnkeyedContainer(forKey: .testarrayoftables)
      for index in 0..<testarrayoftablesCount {
        guard let type = testarrayoftables(at: index) else { continue }
        try contentEncoder.encode(type)
      }
    }
    if inventoryCount > 0 {
      try container.encodeIfPresent(inventory, forKey: .inventory)
    }
    if color != .blue {
      try container.encodeIfPresent(color, forKey: .color)
    }
  }
}

