An Arrow IPC streaming-format reader: the bytes the server sends, without Explorer.
Latu.to_explorer/2 hands its batches to Polars, which is the right answer for a DataFrame
and the wrong one for a tensor — it decodes every column into a Series first. This reads the
same bytes far enough to hand back, per column, sub-binaries of the batch: no copy, and
no interpretation beyond what Arrow itself says. Latu.Result.Nx is what turns those into
tensors, and is the only caller that needs to.
It reads only what Spark sends. A dictionary batch, a compressed body, or a stream whose schema and batches disagree is refused rather than guessed at; refusals are plain strings, because the caller has the column name and the verb and can say more than this can.
What a column comes back as
%{
name: "features",
type: {:float, 64} | {:int, 32, :signed} | :bool | :utf8 | :list | :struct | {:other, _},
length: 4,
null_count: 0,
buffers: [validity_or_nil, ...],
children: [column]
}Buffers are in Arrow's own order for the type — [validity, data] for a primitive,
[validity, offsets] plus one child for a list, [validity] plus N children for a struct —
and a buffer of length zero comes back as nil, which is how Arrow spells "no nulls".
Summary
Types
One record batch: how many rows, and the top-level columns.
One column of one batch: its type, its Arrow buffers, and its children.
A column's type, as Arrow declares it. Anything not named here is {:other, name}.
Functions
Every record batch in one IPC stream.
The schema's top-level column names and types, without reading a batch.
Types
@type batch() :: %{rows: non_neg_integer(), columns: [column()]}
One record batch: how many rows, and the top-level columns.
@type column() :: %{ name: String.t(), type: type(), length: non_neg_integer(), null_count: non_neg_integer(), buffers: [binary() | nil], children: [column()] }
One column of one batch: its type, its Arrow buffers, and its children.
@type type() :: {:int, pos_integer(), :signed | :unsigned} | {:float, 16 | 32 | 64} | :bool | :utf8 | :list | :struct | :null | {:other, atom()}
A column's type, as Arrow declares it. Anything not named here is {:other, name}.
Functions
Every record batch in one IPC stream.
The stream is [schema][batch]…[end-of-stream], which is what one element of
Latu.to_arrow/2 holds. A stream with no batches — an empty result still carries its schema
— answers {:ok, []}.
The schema's top-level column names and types, without reading a batch.