parquet.mojo hands a nested column back as an ArrayData whose children are
indices into an ArrayArena, because Mojo cannot put a List of a struct
inside that same struct. A scan therefore has to carry a whole arena per
column, not one array, and every kernel iceberg.kernels provides for a flat
column needs a counterpart that walks children and offsets.
That is what this module is. A column is a ColumnTree: an arena plus the
index of its root. Each kernel reads one (arena, node) pair and writes its
result into another arena, appending children before their parent — which
keeps a subtree contiguous and ending at its root, the invariant
read.mojo relies on when it moves decoded columns out of a batch.
| kernel |
flat counterpart |
cast_column / cast_tree |
kernels.cast_array |
filter_tree |
kernels.filter_array |
concat_tree |
kernels.concat_into |
null_tree / empty_tree |
kernels.constant_array / empty_array |
flatten_leaf |
— (a struct leaf, seen as a flat column) |
cell_json |
Datum.to_json |
Buffer layouts are Arrow's, exactly as parquet.mojo writes them: a struct
is a validity bitmap and N children of the struct's own length; a list is a
validity bitmap, length + 1 32-bit offsets and one child; a map is a list
whose child is a non-nullable two-field struct (key, value).