# automatically generated by the FlatBuffers compiler, do not modify

# namespace: Example

import flatbuffers
from flatbuffers.compat import import_numpy
from typing import Any
from .MyGame.Example.ArrayStruct import ArrayStruct
from typing import Optional
np = import_numpy()

class ArrayTable(object):
    __slots__ = ['_tab']

    @classmethod
    def GetRootAs(cls, buf, offset: int = 0):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
        x = ArrayTable()
        x.Init(buf, n + offset)
        return x

    @classmethod
    def GetRootAsArrayTable(cls, buf, offset=0):
        """This method is deprecated. Please switch to GetRootAs."""
        return cls.GetRootAs(buf, offset)
    @classmethod
    def ArrayTableBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
        return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x41\x52\x52\x54", size_prefixed=size_prefixed)

    # ArrayTable
    def Init(self, buf: bytes, pos: int):
        self._tab = flatbuffers.table.Table(buf, pos)

    # ArrayTable
    def A(self) -> Optional[ArrayStruct]:
        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
        if o != 0:
            x = o + self._tab.Pos
            obj = ArrayStruct()
            obj.Init(self._tab.Bytes, x)
            return obj
        return None

def ArrayTableStart(builder: flatbuffers.Builder):
    builder.StartObject(1)

def Start(builder: flatbuffers.Builder):
    ArrayTableStart(builder)

def ArrayTableAddA(builder: flatbuffers.Builder, a: Any):
    builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(a), 0)

def AddA(builder: flatbuffers.Builder, a: Any):
    ArrayTableAddA(builder, a)

def ArrayTableEnd(builder: flatbuffers.Builder) -> int:
    return builder.EndObject()

def End(builder: flatbuffers.Builder) -> int:
    return ArrayTableEnd(builder)

import MyGame.Example.ArrayStruct
try:
    from typing import Optional
except:
    pass

class ArrayTableT(object):

    # ArrayTableT
    def __init__(self):
        self.a = None  # type: Optional[MyGame.Example.ArrayStruct.ArrayStructT]

    @classmethod
    def InitFromBuf(cls, buf, pos):
        arrayTable = ArrayTable()
        arrayTable.Init(buf, pos)
        return cls.InitFromObj(arrayTable)

    @classmethod
    def InitFromPackedBuf(cls, buf, pos=0):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, pos)
        return cls.InitFromBuf(buf, pos+n)

    @classmethod
    def InitFromObj(cls, arrayTable):
        x = ArrayTableT()
        x._UnPack(arrayTable)
        return x

    # ArrayTableT
    def _UnPack(self, arrayTable):
        if arrayTable is None:
            return
        if arrayTable.A() is not None:
            self.a = MyGame.Example.ArrayStruct.ArrayStructT.InitFromObj(arrayTable.A())

    # ArrayTableT
    def Pack(self, builder):
        ArrayTableStart(builder)
        if self.a is not None:
            a = self.a.Pack(builder)
            ArrayTableAddA(builder, a)
        arrayTable = ArrayTableEnd(builder)
        return arrayTable
