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

namespace NamespaceA

class TableInFirstNS

namespace NamespaceC

class TableInC

namespace NamespaceA

class SecondTableInA

class TableInFirstNS : flatbuffers_handle
    def foo_table():
        let o = buf_.flatbuffers_field_table(pos_, 4)
        return if o: NamespaceA_NamespaceB_TableInNestedNS { buf_, o } else: nil
    def foo_enum():
        return EnumInNestedNS(buf_.flatbuffers_field_int8(pos_, 6, 0))
    def foo_union_type():
        return UnionInNestedNS(buf_.flatbuffers_field_int8(pos_, 8, 0))
    def foo_union_as_TableInNestedNS():
        return NamespaceA_NamespaceB_TableInNestedNS { buf_, buf_.flatbuffers_field_table(pos_, 10) }
    def foo_struct():
        let o = buf_.flatbuffers_field_struct(pos_, 12)
        return if o: NamespaceA_NamespaceB_StructInNestedNS { buf_, o } else: nil

def GetRootAsTableInFirstNS(buf:string): return TableInFirstNS { buf, buf.flatbuffers_indirect(0) }

struct TableInFirstNSBuilder:
    b_:flatbuffers_builder
    def start():
        b_.StartObject(5)
        return this
    def add_foo_table(foo_table:flatbuffers_offset):
        b_.PrependUOffsetTRelativeSlot(0, foo_table)
        return this
    def add_foo_enum(foo_enum:EnumInNestedNS):
        b_.PrependInt8Slot(1, foo_enum, 0)
        return this
    def add_foo_union_type(foo_union_type:UnionInNestedNS):
        b_.PrependUint8Slot(2, foo_union_type, 0)
        return this
    def add_foo_union(foo_union:flatbuffers_offset):
        b_.PrependUOffsetTRelativeSlot(3, foo_union)
        return this
    def add_foo_struct(foo_struct:flatbuffers_offset):
        b_.PrependStructSlot(4, foo_struct)
        return this
    def end():
        return b_.EndObject()

namespace NamespaceC

class TableInC : flatbuffers_handle
    def refer_to_a1():
        let o = buf_.flatbuffers_field_table(pos_, 4)
        return if o: NamespaceA_TableInFirstNS { buf_, o } else: nil
    def refer_to_a2():
        let o = buf_.flatbuffers_field_table(pos_, 6)
        return if o: NamespaceA_SecondTableInA { buf_, o } else: nil

def GetRootAsTableInC(buf:string): return TableInC { buf, buf.flatbuffers_indirect(0) }

struct TableInCBuilder:
    b_:flatbuffers_builder
    def start():
        b_.StartObject(2)
        return this
    def add_refer_to_a1(refer_to_a1:flatbuffers_offset):
        b_.PrependUOffsetTRelativeSlot(0, refer_to_a1)
        return this
    def add_refer_to_a2(refer_to_a2:flatbuffers_offset):
        b_.PrependUOffsetTRelativeSlot(1, refer_to_a2)
        return this
    def end():
        return b_.EndObject()

namespace NamespaceA

class SecondTableInA : flatbuffers_handle
    def refer_to_c():
        let o = buf_.flatbuffers_field_table(pos_, 4)
        return if o: NamespaceC_TableInC { buf_, o } else: nil

def GetRootAsSecondTableInA(buf:string): return SecondTableInA { buf, buf.flatbuffers_indirect(0) }

struct SecondTableInABuilder:
    b_:flatbuffers_builder
    def start():
        b_.StartObject(1)
        return this
    def add_refer_to_c(refer_to_c:flatbuffers_offset):
        b_.PrependUOffsetTRelativeSlot(0, refer_to_c)
        return this
    def end():
        return b_.EndObject()

