# arrow_mlake.carrow

> A module of arrow-mlake's API.

The Arrow C Data Interface — this library's public output contract.

`export_c` turns one `ArrayData` tree into the two C structs every Arrow
implementation understands:

```c
struct ArrowSchema { const char* format; const char* name; const char* metadata;
                     int64_t flags; int64_t n_children; ArrowSchema** children;
                     ArrowSchema* dictionary; void (*release)(ArrowSchema*);
                     void* private_data; };
struct ArrowArray  { int64_t length; int64_t null_count; int64_t offset;
                     int64_t n_buffers; int64_t n_children; const void** buffers;
                     ArrowArray** children; ArrowArray* dictionary;
                     void (*release)(ArrowArray*); void* private_data; };
```

Each export is **two** allocations — one for the whole schema tree, one for the
whole array tree — laid out as: the structs, then the pointer arrays, then the
format and name strings and the metadata blocks, then copies of every buffer.
The root's `private_data` is the base of its block and its `release` frees the
lot; children carry a release that only clears itself, because a consumer
releases the root and the root owns everything. Both callbacks are `abi("C")`,
so they can be called from C, Python or Rust.

Buffers are copied rather than borrowed, which is what makes the export
outlive the `RecordBatch` it came from and makes `ExportedArray` safe to hand
to a runtime that will release it whenever it likes.

```mojo
var e = export_c(batch.arena, batch.roots[0])
print(e.array, e.schema)   # two addresses, ready for _import_from_c
e.into_raw()               # hand ownership to the consumer
```

`arrow_mlake.carrow_import` is the other direction — a foreign `ArrowSchema`
and `ArrowArray` read back into an `ArrayData`, and `ArrowArrayStream`
iterated — and it implements the consumer's half of the same release
convention.

## Structs

### `CArrowSchema`

```mojo
struct CArrowSchema
```

The C `ArrowSchema`, field for field. Pointers are held as addresses.

Implements: `Copyable`, `Movable`

Fields:

- `format: Int`
- `name: Int`
- `metadata: Int`
- `flags: Int64`
- `n_children: Int64`
- `children: Int`
- `dictionary: Int`
- `release: Int`
- `private_data: Int`

### `CArrowArray`

```mojo
struct CArrowArray
```

The C `ArrowArray`, field for field. Pointers are held as addresses.

Implements: `Copyable`, `Movable`

Fields:

- `length: Int64`
- `null_count: Int64`
- `offset: Int64`
- `n_buffers: Int64`
- `n_children: Int64`
- `buffers: Int`
- `children: Int`
- `dictionary: Int`
- `release: Int`
- `private_data: Int`

### `ExportedArray`

```mojo
struct ExportedArray
```

An exported pair of C structs, still owned by Mojo until `into_raw`.

Implements: `Movable`

Fields:

- `array: Int`: Address of the `ArrowArray`.
- `schema: Int`: Address of the `ArrowSchema`.

#### `__init__`

```mojo
def __init__(out self, array: Int, schema: Int)
```

#### `__deinit__`

```mojo
def __deinit__(deinit self)
```

#### `into_raw`

```mojo
def into_raw(mut self) -> Tuple[Int, Int]
```

Give the two structs to the consumer; they must release them.

#### `release`

```mojo
def release(mut self)
```

## Functions

### `release_array`

```mojo
def release_array(p: Pointer[CArrowArray, MutUntrackedOrigin])
```

Free the whole exported array tree. `private_data` is the block.

### `release_schema`

```mojo
def release_schema(p: Pointer[CArrowSchema, MutUntrackedOrigin])
```

Free the whole exported schema tree.

### `release_child_array`

```mojo
def release_child_array(p: Pointer[CArrowArray, MutUntrackedOrigin])
```

A child is owned by its root; releasing one only marks it released.

### `release_child_schema`

```mojo
def release_child_schema(p: Pointer[CArrowSchema, MutUntrackedOrigin])
```

### `n_buffers_for_type`

```mojo
def n_buffers_for_type(i: Int) -> Int
```

How many buffers an `ArrowArray` of this type id must carry.

The export writes this many and `arrow_mlake.carrow_import` rejects a
producer that sends any other number, so the count is stated once rather
than twice.

### `n_buffers_for`

```mojo
def n_buffers_for(a: ArrayData) -> Int
```

### `export_c`

```mojo
def export_c(arena: ArrayArena, root: Int) -> ExportedArray
```

Export one array of an arena over the Arrow C Data Interface.

## Aliases

### `ARROW_FLAG_NULLABLE`

```mojo
comptime ARROW_FLAG_NULLABLE = Int64(2)
```

### `SchemaReleaseFn`

```mojo
comptime SchemaReleaseFn = def(Pointer[CArrowSchema, MutUntrackedOrigin]) abi("C") thin -> None
```

### `ArrayReleaseFn`

```mojo
comptime ArrayReleaseFn = def(Pointer[CArrowArray, MutUntrackedOrigin]) abi("C") thin -> None
```
