# arrow_mlake.flatbuf

> A module of arrow-mlake's API.

FlatBuffers, as much as Arrow IPC metadata needs: a builder and a reader.

**The builder** came from flight.mojo, where it wrote `Schema` and
`RecordBatch` messages. Writing means we choose the layout, so it only has to
be self-consistent and spec-legal. Buffers are built back to front: `_head`
starts at the end of the storage and walks downwards, so the root table ends
up nearest the front and every child it points at is already written behind
it. `offset()` is "bytes written so far", measured from the end, and every
stored offset is a backwards distance from the field to its target, which is
why `_ref` subtracts.

A table is written as: field data, then a vtable listing where each field
landed, then a signed backwards offset from the table to that vtable. Absent
fields are simply not written. There is no vtable deduplication; Arrow
messages are small.

**The reader** takes whatever layout a producer chose, so it trusts nothing:
every offset is bounds-checked before it is followed, and a field the vtable
doesn't reach reads as absent. It copies the message into a `FlatReader`
rather than borrowing it, because IPC metadata is a few hundred bytes and an
owned buffer keeps origins out of the API.

## Structs

### `FlatBufferBuilder`

```mojo
struct FlatBufferBuilder
```

Builds one FlatBuffer, back to front.

Not reusable: `finish` leaves the builder holding the completed buffer,
and the intended lifecycle is one builder per message.

Implements: `Movable`

#### `__init__`

```mojo
def __init__(out self, initial: Int = Int(1024))
```

#### `offset`

```mojo
def offset(self) -> Int
```

Bytes written so far, which is also the position of the next write measured from the end of the buffer.

#### `prepend_u8`

```mojo
def prepend_u8(mut self, v: UInt8)
```

#### `prepend_bool`

```mojo
def prepend_bool(mut self, v: Bool)
```

#### `prepend_i16`

```mojo
def prepend_i16(mut self, v: Int)
```

#### `prepend_i32`

```mojo
def prepend_i32(mut self, v: Int)
```

#### `prepend_i64`

```mojo
def prepend_i64(mut self, v: Int)
```

#### `start_table`

```mojo
def start_table(mut self, num_slots: Int)
```

#### `add_bool`

```mojo
def add_bool(mut self, slot: Int, v: Bool, default: Bool = False)
```

Add a field, unless it already holds the schema default.

Omitting defaults is not just a size trick: a reader that asks for an
absent field gets the default back, so writing it would be identical
but larger.

#### `add_i16`

```mojo
def add_i16(mut self, slot: Int, v: Int, default: Int = Int(0))
```

#### `add_i32`

```mojo
def add_i32(mut self, slot: Int, v: Int, default: Int = Int(0))
```

#### `add_i64`

```mojo
def add_i64(mut self, slot: Int, v: Int, default: Int = Int(0))
```

#### `add_u8`

```mojo
def add_u8(mut self, slot: Int, v: UInt8, default: UInt8 = UInt8(0))
```

#### `add_offset`

```mojo
def add_offset(mut self, slot: Int, target: Int)
```

Add a reference field (table, string or vector). `0` means absent.

#### `end_table`

```mojo
def end_table(mut self) -> Int
```

Finish the table and return its offset.

Writes the vtable, then the table's own backwards pointer to it. The
vtable is trimmed to the last field actually set, which is what lets a
reader of a longer schema see the extra fields as absent rather than
as garbage.

#### `create_string`

```mojo
def create_string(mut self, s: String) -> Int
```

Write a length-prefixed, NUL-terminated UTF-8 string.

#### `start_vector`

```mojo
def start_vector(mut self, elem_size: Int, count: Int, align: Int)
```

Begin a vector; elements are prepended in reverse order.

#### `end_vector`

```mojo
def end_vector(mut self) -> Int
```

#### `create_offset_vector`

```mojo
def create_offset_vector(mut self, offsets: List[Int]) -> Int
```

A vector of references, written back to front.

#### `finish`

```mojo
def finish(mut self, root: Int) -> List[UInt8]
```

Write the root offset and return the finished buffer.

### `FlatReader`

```mojo
struct FlatReader
```

One FlatBuffer, read through absolute byte positions.

Tables, vectors and strings are named by where they start in the buffer.
A position of 0 means absent: no table can start there, because the
buffer starts with the root offset.

Implements: `Movable`

Fields:

- `buf: List[UInt8]`

#### `__init__`

```mojo
def __init__(out self, var buf: List[UInt8])
```

#### `u8`

```mojo
def u8(self, pos: Int) -> Int
```

#### `u16`

```mojo
def u16(self, pos: Int) -> Int
```

#### `u32`

```mojo
def u32(self, pos: Int) -> Int
```

#### `i16`

```mojo
def i16(self, pos: Int) -> Int
```

#### `i32`

```mojo
def i32(self, pos: Int) -> Int
```

#### `i64`

```mojo
def i64(self, pos: Int) -> Int
```

#### `root`

```mojo
def root(self) -> Int
```

Where the root table starts.

#### `field`

```mojo
def field(self, table: Int, slot: Int) -> Int
```

Where field `slot` of `table` is stored, or 0 if it's absent.

#### `get_bool`

```mojo
def get_bool(self, table: Int, slot: Int, default: Bool = False) -> Bool
```

#### `get_u8`

```mojo
def get_u8(self, table: Int, slot: Int, default: Int = Int(0)) -> Int
```

#### `get_i16`

```mojo
def get_i16(self, table: Int, slot: Int, default: Int = Int(0)) -> Int
```

#### `get_i32`

```mojo
def get_i32(self, table: Int, slot: Int, default: Int = Int(0)) -> Int
```

#### `get_i64`

```mojo
def get_i64(self, table: Int, slot: Int, default: Int = Int(0)) -> Int
```

#### `get_ref`

```mojo
def get_ref(self, table: Int, slot: Int) -> Int
```

Follow a table, vector or string field; 0 if it's absent.

#### `get_string`

```mojo
def get_string(self, table: Int, slot: Int) -> String
```

A string field, or "" if it's absent.

#### `vector_len`

```mojo
def vector_len(self, vector: Int) -> Int
```

#### `vector_table`

```mojo
def vector_table(self, vector: Int, i: Int) -> Int
```

Element `i` of a vector of tables.

#### `vector_struct`

```mojo
def vector_struct(self, vector: Int, i: Int, size: Int) -> Int
```

Where element `i` of a vector of `size`-byte structs starts.
