@@ -55,9 +55,17 @@ shortcut returning a nullable copy), `withNullable(boolean)`, `DType.Struct.fiel
5555
5656---
5757
58+ ### Identity types (` io.github.dfa1.vortex.core.model ` )
59+
60+ | Type | Shape | Notes |
61+ | ------| -------| -------|
62+ | ` EncodingId ` | ` sealed interface ` — ` WellKnown ` enum + ` Custom ` record | Array-encoding identity; total ` parse(String) ` over non-blank ids; constants re-exported (` EncodingId.VORTEX_PRIMITIVE ` , …) |
63+ | ` LayoutId ` | ` sealed interface ` — ` WellKnown ` enum + ` Custom ` record | Layout identity (separate namespace from encodings; ` vortex.flat ` is layout-only); both zoned aliases ` vortex.zoned ` /` vortex.stats ` |
64+ | ` ColumnName ` | ` record ColumnName(String value) ` | Validated column name: non-blank, no control characters. ` ColumnName.violation(String) ` is the policy chokepoint shared by builder, writer, and file parser |
65+
5866## Reader API
5967
60- ### ` VortexReader ` (` io.github.dfa1.vortex.io .VortexReader ` )
68+ ### ` VortexReader ` (` io.github.dfa1.vortex.reader .VortexReader ` )
6169
6270Memory-mapped handle to a Vortex file. Implements ` AutoCloseable ` . Closing releases the mmap region;
6371all ` Array ` buffers obtained during scans become invalid.
@@ -66,6 +74,7 @@ all `Array` buffers obtained during scans become invalid.
6674| ---------------------------------------| ---------------------------| -----------------------------------------------|
6775| ` static open(Path) ` | ` VortexReader ` | Uses ` ReadRegistry.loadAll() ` |
6876| ` static open(Path, ReadRegistry) ` | ` VortexReader ` | Custom registry (e.g. ` allowUnknown() ` ) |
77+ | ` static open(Path, ReadRegistry, LayoutRegistry) ` | ` VortexReader ` | Custom layout decoders too |
6978| ` dtype() ` | ` DType ` | Schema (typically ` DType.Struct ` ) |
7079| ` layout() ` | ` Layout ` | Layout tree (Struct → Zoned → Chunked → Flat) |
7180| ` footer() ` | ` Footer ` | Segment specs, encoding specs |
@@ -127,7 +136,7 @@ Record: `(int chunkSize, boolean enableZoneMaps, double compressionRatioThreshol
127136
128137## Scan API
129138
130- ### ` ScanOptions ` (` io.github.dfa1.vortex.scan .ScanOptions ` )
139+ ### ` ScanOptions ` (` io.github.dfa1.vortex.reader .ScanOptions ` )
131140
132141Record: ` (List<String> columns, RowFilter rowFilter, long limit) ` . Empty ` columns ` = read all. ` NO_LIMIT ` =
133142` Long.MAX_VALUE ` .
@@ -142,7 +151,7 @@ Record: `(List<String> columns, RowFilter rowFilter, long limit)`. Empty `column
142151| ` .withLimit(long n) ` | Cap rows |
143152| ` .hasProjection() ` / ` .hasFilter() ` / ` .hasLimit() ` | Predicates |
144153
145- ### ` RowFilter ` (` io.github.dfa1.vortex.scan .RowFilter ` )
154+ ### ` RowFilter ` (` io.github.dfa1.vortex.reader .RowFilter ` )
146155
147156Sealed predicate used for zone-map pruning (per-chunk min/max). Chunks that cannot match are skipped entirely.
148157
@@ -156,7 +165,7 @@ Sealed predicate used for zone-map pruning (per-chunk min/max). Chunks that cann
156165| ` RowFilter.Neq(column, value) ` | ` RowFilter.neq(col, val) ` | — |
157166| ` RowFilter.And(filters) ` | ` RowFilter.and(f1, f2, …) ` | ` f1.and(f2) ` |
158167
159- ### ` ScanIterator ` (` io.github.dfa1.vortex.scan .ScanIterator ` )
168+ ### ` ScanIterator ` (` io.github.dfa1.vortex.reader .ScanIterator ` )
160169
161170Implements ` Iterator<Chunk> ` and ` AutoCloseable ` . Drives one scan.
162171
@@ -167,7 +176,7 @@ Implements `Iterator<Chunk>` and `AutoCloseable`. Drives one scan.
167176| ` forEachRemaining(Consumer) ` | Overridden to wrap each ` next() ` in try-with-resources so chunks auto-close. |
168177| ` close() ` | Releases iterator state and closes any chunk still open. |
169178
170- ### ` Chunk ` (` io.github.dfa1.vortex.scan .Chunk ` )
179+ ### ` Chunk ` (` io.github.dfa1.vortex.reader .Chunk ` )
171180
172181Implements ` AutoCloseable ` . Each chunk owns a confined ` Arena ` holding the decoded
173182columnar buffers; closing the chunk releases the arena. After ` close() ` , touching
@@ -214,6 +223,27 @@ implementations are singletons invoked directly by their `ExtensionId`.
214223
215224---
216225
226+ ## Layout registry
227+
228+ ### ` LayoutRegistry ` (` io.github.dfa1.vortex.reader.layout ` )
229+
230+ Maps ` LayoutId ` → ` LayoutDecoder ` , making layout decode pluggable the way ` ReadRegistry ` makes
231+ encodings pluggable. Programmatic registration only — no ` ServiceLoader ` . Unknown layouts fail
232+ loudly (` VortexException ` ); there is no allow-unknown mode for layouts (Rust default).
233+
234+ | Method | Notes |
235+ | -----------------------------| --------------------------------------------------------------------|
236+ | ` static defaults() ` | The four built-ins: flat, chunked, zoned (both aliases), dict |
237+ | ` static builder() ` | Returns a fresh ` Builder ` |
238+ | ` hasDecoder(LayoutId) ` | Lookup |
239+ | ` decode(ctx, layout, dtype) ` | Dispatch by the layout's typed id |
240+
241+ ` Builder ` : ` register(LayoutDecoder) ` (throws on duplicate id), ` registerDefaults() ` , ` build() ` .
242+ A decoder claims its ids via ` LayoutDecoder.layoutIds() ` (a set — the zoned decoder claims both
243+ ` vortex.zoned ` and legacy ` vortex.stats ` ). Custom decoders receive a ` LayoutDecodeContext `
244+ (` decodeChild ` , ` decodeSegment ` access, ` arena ` ) and are reachable end-to-end via
245+ ` VortexReader.open(path, readRegistry, layoutRegistry) ` .
246+
217247## Parquet / CSV import
218248
219249### ` ParquetImporter ` (` io.github.dfa1.vortex.parquet.ParquetImporter ` )
0 commit comments