Skip to content

Commit ea88a91

Browse files
dfa1claude
andcommitted
refactor(core): EncodingId becomes a sealed interface
sealed interface EncodingId permits WellKnown, Custom: the spec constants move verbatim into the nested WellKnown enum and every wire string now has a typed representation — parse() is total, returning the WellKnown match or a Custom wrapping the raw id. Custom's compact constructor rejects null, blank, and ids that collide with a WellKnown wire string, so the two variants never alias as map keys. All constants are re-exported as WellKnown-typed interface fields, keeping the existing EncodingId.VORTEX_FOO call sites source compatible. KnownArrayNode narrows its component to WellKnown (a known node can no longer hold a custom id); ArrayNode.of dispatches WellKnown/Custom to Known/UnknownArrayNode. EncodingDecoder and EncodingEncoder keep the interface in their signatures, which for the first time lets third-party codecs declare ids outside the spec set. EncodingId extends Serializable to preserve the enum's implicit serializability for the VortexException field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent f2cbd22 commit ea88a91

8 files changed

Lines changed: 302 additions & 135 deletions

File tree

Lines changed: 220 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,235 @@
11
package io.github.dfa1.vortex.core.model;
22

3+
import java.io.Serializable;
34
import java.util.Map;
4-
import java.util.Optional;
5+
import java.util.Objects;
56
import java.util.function.Function;
67
import java.util.stream.Collectors;
78
import java.util.stream.Stream;
89

9-
/// Strongly-typed encoding identifier used in place of raw strings.
10-
public enum EncodingId {
11-
/// Canonical flat primitive encoding (`vortex.primitive`).
12-
VORTEX_PRIMITIVE("vortex.primitive"),
13-
/// Bit-packed boolean encoding (`vortex.bool`).
14-
VORTEX_BOOL("vortex.bool"),
15-
/// Dictionary encoding for low-cardinality columns (`vortex.dict`).
16-
VORTEX_DICT("vortex.dict"),
17-
/// Sparse encoding for columns with many nulls or zeros (`vortex.sparse`).
18-
VORTEX_SPARSE("vortex.sparse"),
19-
/// Sequence encoding (`vortex.sequence`).
20-
VORTEX_SEQUENCE("vortex.sequence"),
21-
/// Run-end encoding for sorted/repetitive columns (`vortex.runend`).
22-
VORTEX_RUNEND("vortex.runend"),
23-
/// Constant encoding — all elements share one value (`vortex.constant`).
24-
VORTEX_CONSTANT("vortex.constant"),
25-
/// ALP (Adaptive Lossless floating-Point) encoding for F32/F64 (`vortex.alp`).
26-
VORTEX_ALP("vortex.alp"),
27-
/// Variable-length binary encoding (`vortex.varbin`).
28-
VORTEX_VARBIN("vortex.varbin"),
29-
/// FSST compressed string encoding (`vortex.fsst`).
30-
VORTEX_FSST("vortex.fsst"),
31-
/// All-null encoding (`vortex.null`).
32-
VORTEX_NULL("vortex.null"),
33-
/// One-byte-per-boolean encoding (`vortex.bytebool`).
34-
VORTEX_BYTEBOOL("vortex.bytebool"),
35-
/// Zig-zag encoding for signed integers (`vortex.zigzag`).
36-
VORTEX_ZIGZAG("vortex.zigzag"),
37-
/// Extension type wrapper encoding (`vortex.ext`).
38-
VORTEX_EXT("vortex.ext"),
39-
/// Variable-length binary view encoding (`vortex.varbinview`).
40-
VORTEX_VARBINVIEW("vortex.varbinview"),
41-
/// pcodec (Pco) floating-point/integer encoding (`vortex.pco`).
42-
VORTEX_PCO("vortex.pco"),
43-
/// Canonical flat decimal storage (`vortex.decimal`).
44-
VORTEX_DECIMAL("vortex.decimal"),
45-
/// Decimal split into MSP + LSP children (`vortex.decimal_byte_parts`).
46-
VORTEX_DECIMAL_BYTE_PARTS("vortex.decimal_byte_parts"),
47-
/// Timestamp split into days/seconds/subseconds (`vortex.datetimeparts`).
48-
VORTEX_DATETIMEPARTS("vortex.datetimeparts"),
49-
/// Zstandard compressed encoding (`vortex.zstd`).
50-
VORTEX_ZSTD("vortex.zstd"),
51-
/// Fixed-size list encoding (`vortex.fixed_size_list`).
52-
VORTEX_FIXED_SIZE_LIST("vortex.fixed_size_list"),
53-
/// Variable-length list encoding (`vortex.list`).
54-
VORTEX_LIST("vortex.list"),
55-
/// List-view encoding (`vortex.listview`).
56-
VORTEX_LISTVIEW("vortex.listview"),
57-
/// ALP-RD (ALP with remainder dictionary) encoding (`vortex.alprd`).
58-
VORTEX_ALPRD("vortex.alprd"),
59-
60-
// Layout encoding IDs included so parser/registry can represent them safely
61-
/// Chunked layout encoding (`vortex.chunked`).
62-
VORTEX_CHUNKED("vortex.chunked"),
63-
/// Struct layout encoding (`vortex.struct`).
64-
VORTEX_STRUCT("vortex.struct"),
65-
66-
/// FastLanes bit-packed encoding (`fastlanes.bitpacked`).
67-
FASTLANES_BITPACKED("fastlanes.bitpacked"),
68-
/// FastLanes frame-of-reference encoding (`fastlanes.for`).
69-
FASTLANES_FOR("fastlanes.for"),
70-
/// FastLanes delta encoding (`fastlanes.delta`).
71-
FASTLANES_DELTA("fastlanes.delta"),
72-
/// FastLanes run-length encoding (`fastlanes.rle`).
73-
FASTLANES_RLE("fastlanes.rle"),
74-
75-
/// Masked encoding (`vortex.masked`): payload child plus optional validity bitmap child.
76-
VORTEX_MASKED("vortex.masked"),
77-
/// Patched encoding (`vortex.patched`): base child with sparse positional patch overrides.
78-
VORTEX_PATCHED("vortex.patched"),
79-
/// Variant logical encoding: canonical container over `core_storage` plus an optional shredded child.
80-
VORTEX_VARIANT("vortex.variant"),
81-
;
82-
83-
// O(1) access to EncodingId by its string representation
84-
private static final Map<String, EncodingId> LOOKUP = Stream.of(EncodingId.values())
85-
.collect(Collectors.toUnmodifiableMap(EncodingId::id, Function.identity()));
86-
private final String id;
87-
88-
EncodingId(String id) {
89-
this.id = id;
90-
}
10+
/// Identity of an array encoding — either a spec [WellKnown] constant or a third-party [Custom] id.
11+
///
12+
/// The wire representation is always a string (e.g. `"vortex.flat"`); [#parse(String)] maps any
13+
/// such string to a typed value, and [#id()] recovers the wire string from a typed value.
14+
///
15+
/// Extends [Serializable] so a [Custom] or [WellKnown] carried on a
16+
/// [io.github.dfa1.vortex.core.error.VortexException] survives serialization, matching the prior
17+
/// enum's implicit serializability.
18+
public sealed interface EncodingId extends Serializable permits EncodingId.WellKnown, EncodingId.Custom {
9119

92-
/// Parses a raw encoding id string into the matching constant.
93-
/// Used by `ReadRegistry` to discriminate `KnownArrayNode` from `UnknownArrayNode`;
94-
/// callers that demand a known id chain `.orElseThrow(...)`.
20+
/// Returns the wire string of this encoding id (e.g. `"vortex.flat"`).
9521
///
96-
/// @param id raw encoding id string (e.g. `"vortex.primitive"`)
97-
/// @return matching constant, or empty if not recognized
98-
public static Optional<EncodingId> parse(String id) {
99-
return Optional.ofNullable(LOOKUP.get(id));
100-
}
22+
/// @return the wire string of this encoding id
23+
String id();
10124

102-
/// Returns the raw encoding id string for this constant (e.g. `"vortex.primitive"`).
25+
/// Total parse: every non-null string has a typed representation.
26+
/// Returns the matching [WellKnown] constant, else a [Custom] wrapping the raw string.
10327
///
104-
/// @return the raw string encoding id
105-
public String id() {
106-
return id;
28+
/// @param raw the raw encoding id string (e.g. `"vortex.primitive"`)
29+
/// @return the matching [WellKnown] constant, or a [Custom] wrapping `raw` if none matches
30+
static EncodingId parse(String raw) {
31+
WellKnown known = WellKnown.byId(raw);
32+
return known != null ? known : new Custom(raw);
10733
}
10834

109-
@Override
110-
public String toString() {
111-
return id;
35+
/// Encoding ids defined by the Vortex specification and understood by this build.
36+
enum WellKnown implements EncodingId {
37+
/// Canonical flat primitive encoding (`vortex.primitive`).
38+
VORTEX_PRIMITIVE("vortex.primitive"),
39+
/// Bit-packed boolean encoding (`vortex.bool`).
40+
VORTEX_BOOL("vortex.bool"),
41+
/// Dictionary encoding for low-cardinality columns (`vortex.dict`).
42+
VORTEX_DICT("vortex.dict"),
43+
/// Sparse encoding for columns with many nulls or zeros (`vortex.sparse`).
44+
VORTEX_SPARSE("vortex.sparse"),
45+
/// Sequence encoding (`vortex.sequence`).
46+
VORTEX_SEQUENCE("vortex.sequence"),
47+
/// Run-end encoding for sorted/repetitive columns (`vortex.runend`).
48+
VORTEX_RUNEND("vortex.runend"),
49+
/// Constant encoding — all elements share one value (`vortex.constant`).
50+
VORTEX_CONSTANT("vortex.constant"),
51+
/// ALP (Adaptive Lossless floating-Point) encoding for F32/F64 (`vortex.alp`).
52+
VORTEX_ALP("vortex.alp"),
53+
/// Variable-length binary encoding (`vortex.varbin`).
54+
VORTEX_VARBIN("vortex.varbin"),
55+
/// FSST compressed string encoding (`vortex.fsst`).
56+
VORTEX_FSST("vortex.fsst"),
57+
/// All-null encoding (`vortex.null`).
58+
VORTEX_NULL("vortex.null"),
59+
/// One-byte-per-boolean encoding (`vortex.bytebool`).
60+
VORTEX_BYTEBOOL("vortex.bytebool"),
61+
/// Zig-zag encoding for signed integers (`vortex.zigzag`).
62+
VORTEX_ZIGZAG("vortex.zigzag"),
63+
/// Extension type wrapper encoding (`vortex.ext`).
64+
VORTEX_EXT("vortex.ext"),
65+
/// Variable-length binary view encoding (`vortex.varbinview`).
66+
VORTEX_VARBINVIEW("vortex.varbinview"),
67+
/// pcodec (Pco) floating-point/integer encoding (`vortex.pco`).
68+
VORTEX_PCO("vortex.pco"),
69+
/// Canonical flat decimal storage (`vortex.decimal`).
70+
VORTEX_DECIMAL("vortex.decimal"),
71+
/// Decimal split into MSP + LSP children (`vortex.decimal_byte_parts`).
72+
VORTEX_DECIMAL_BYTE_PARTS("vortex.decimal_byte_parts"),
73+
/// Timestamp split into days/seconds/subseconds (`vortex.datetimeparts`).
74+
VORTEX_DATETIMEPARTS("vortex.datetimeparts"),
75+
/// Zstandard compressed encoding (`vortex.zstd`).
76+
VORTEX_ZSTD("vortex.zstd"),
77+
/// Fixed-size list encoding (`vortex.fixed_size_list`).
78+
VORTEX_FIXED_SIZE_LIST("vortex.fixed_size_list"),
79+
/// Variable-length list encoding (`vortex.list`).
80+
VORTEX_LIST("vortex.list"),
81+
/// List-view encoding (`vortex.listview`).
82+
VORTEX_LISTVIEW("vortex.listview"),
83+
/// ALP-RD (ALP with remainder dictionary) encoding (`vortex.alprd`).
84+
VORTEX_ALPRD("vortex.alprd"),
85+
86+
// Layout encoding IDs included so parser/registry can represent them safely
87+
/// Chunked layout encoding (`vortex.chunked`).
88+
VORTEX_CHUNKED("vortex.chunked"),
89+
/// Struct layout encoding (`vortex.struct`).
90+
VORTEX_STRUCT("vortex.struct"),
91+
92+
/// FastLanes bit-packed encoding (`fastlanes.bitpacked`).
93+
FASTLANES_BITPACKED("fastlanes.bitpacked"),
94+
/// FastLanes frame-of-reference encoding (`fastlanes.for`).
95+
FASTLANES_FOR("fastlanes.for"),
96+
/// FastLanes delta encoding (`fastlanes.delta`).
97+
FASTLANES_DELTA("fastlanes.delta"),
98+
/// FastLanes run-length encoding (`fastlanes.rle`).
99+
FASTLANES_RLE("fastlanes.rle"),
100+
101+
/// Masked encoding (`vortex.masked`): payload child plus optional validity bitmap child.
102+
VORTEX_MASKED("vortex.masked"),
103+
/// Patched encoding (`vortex.patched`): base child with sparse positional patch overrides.
104+
VORTEX_PATCHED("vortex.patched"),
105+
/// Variant logical encoding: canonical container over `core_storage` plus an optional shredded child.
106+
VORTEX_VARIANT("vortex.variant"),
107+
;
108+
109+
// O(1) access to a WellKnown constant by its string representation
110+
private static final Map<String, WellKnown> LOOKUP = Stream.of(values())
111+
.collect(Collectors.toUnmodifiableMap(WellKnown::id, Function.identity()));
112+
private final String id;
113+
114+
WellKnown(String id) {
115+
this.id = id;
116+
}
117+
118+
/// Returns the well-known constant whose wire string is `id`, or `null` if none matches.
119+
///
120+
/// @param id the wire string to look up (may be `null`)
121+
/// @return the matching constant, or `null` if unrecognized
122+
static WellKnown byId(String id) {
123+
return LOOKUP.get(id);
124+
}
125+
126+
@Override
127+
public String id() {
128+
return id;
129+
}
130+
131+
@Override
132+
public String toString() {
133+
return id;
134+
}
135+
}
136+
137+
/// A third-party encoding id whose wire string is not part of the [WellKnown] set.
138+
///
139+
/// @param id the wire string of this encoding id; must be non-blank and must not collide
140+
/// with a [WellKnown] wire string
141+
record Custom(String id) implements EncodingId {
142+
143+
/// Validates that `id` is a usable custom encoding id.
144+
///
145+
/// @param id the wire string of this encoding id
146+
/// @throws NullPointerException if `id` is `null`
147+
/// @throws IllegalArgumentException if `id` is blank or matches a [WellKnown] wire string
148+
public Custom {
149+
Objects.requireNonNull(id, "id");
150+
if (id.isBlank()) {
151+
throw new IllegalArgumentException("encoding id must not be blank");
152+
}
153+
WellKnown wellKnown = WellKnown.byId(id);
154+
if (wellKnown != null) {
155+
throw new IllegalArgumentException(
156+
"\"" + id + "\" is a well-known encoding id; use EncodingId." + wellKnown.name() + " instead");
157+
}
158+
}
159+
160+
@Override
161+
public String toString() {
162+
return id;
163+
}
112164
}
165+
166+
// Re-export every WellKnown constant, typed as WellKnown, so existing `EncodingId.VORTEX_FOO`
167+
// call sites keep compiling and remain usable wherever a WellKnown is required.
168+
169+
/// Well-known `vortex.primitive` id.
170+
WellKnown VORTEX_PRIMITIVE = WellKnown.VORTEX_PRIMITIVE;
171+
/// Well-known `vortex.bool` id.
172+
WellKnown VORTEX_BOOL = WellKnown.VORTEX_BOOL;
173+
/// Well-known `vortex.dict` id.
174+
WellKnown VORTEX_DICT = WellKnown.VORTEX_DICT;
175+
/// Well-known `vortex.sparse` id.
176+
WellKnown VORTEX_SPARSE = WellKnown.VORTEX_SPARSE;
177+
/// Well-known `vortex.sequence` id.
178+
WellKnown VORTEX_SEQUENCE = WellKnown.VORTEX_SEQUENCE;
179+
/// Well-known `vortex.runend` id.
180+
WellKnown VORTEX_RUNEND = WellKnown.VORTEX_RUNEND;
181+
/// Well-known `vortex.constant` id.
182+
WellKnown VORTEX_CONSTANT = WellKnown.VORTEX_CONSTANT;
183+
/// Well-known `vortex.alp` id.
184+
WellKnown VORTEX_ALP = WellKnown.VORTEX_ALP;
185+
/// Well-known `vortex.varbin` id.
186+
WellKnown VORTEX_VARBIN = WellKnown.VORTEX_VARBIN;
187+
/// Well-known `vortex.fsst` id.
188+
WellKnown VORTEX_FSST = WellKnown.VORTEX_FSST;
189+
/// Well-known `vortex.null` id.
190+
WellKnown VORTEX_NULL = WellKnown.VORTEX_NULL;
191+
/// Well-known `vortex.bytebool` id.
192+
WellKnown VORTEX_BYTEBOOL = WellKnown.VORTEX_BYTEBOOL;
193+
/// Well-known `vortex.zigzag` id.
194+
WellKnown VORTEX_ZIGZAG = WellKnown.VORTEX_ZIGZAG;
195+
/// Well-known `vortex.ext` id.
196+
WellKnown VORTEX_EXT = WellKnown.VORTEX_EXT;
197+
/// Well-known `vortex.varbinview` id.
198+
WellKnown VORTEX_VARBINVIEW = WellKnown.VORTEX_VARBINVIEW;
199+
/// Well-known `vortex.pco` id.
200+
WellKnown VORTEX_PCO = WellKnown.VORTEX_PCO;
201+
/// Well-known `vortex.decimal` id.
202+
WellKnown VORTEX_DECIMAL = WellKnown.VORTEX_DECIMAL;
203+
/// Well-known `vortex.decimal_byte_parts` id.
204+
WellKnown VORTEX_DECIMAL_BYTE_PARTS = WellKnown.VORTEX_DECIMAL_BYTE_PARTS;
205+
/// Well-known `vortex.datetimeparts` id.
206+
WellKnown VORTEX_DATETIMEPARTS = WellKnown.VORTEX_DATETIMEPARTS;
207+
/// Well-known `vortex.zstd` id.
208+
WellKnown VORTEX_ZSTD = WellKnown.VORTEX_ZSTD;
209+
/// Well-known `vortex.fixed_size_list` id.
210+
WellKnown VORTEX_FIXED_SIZE_LIST = WellKnown.VORTEX_FIXED_SIZE_LIST;
211+
/// Well-known `vortex.list` id.
212+
WellKnown VORTEX_LIST = WellKnown.VORTEX_LIST;
213+
/// Well-known `vortex.listview` id.
214+
WellKnown VORTEX_LISTVIEW = WellKnown.VORTEX_LISTVIEW;
215+
/// Well-known `vortex.alprd` id.
216+
WellKnown VORTEX_ALPRD = WellKnown.VORTEX_ALPRD;
217+
/// Well-known `vortex.chunked` id.
218+
WellKnown VORTEX_CHUNKED = WellKnown.VORTEX_CHUNKED;
219+
/// Well-known `vortex.struct` id.
220+
WellKnown VORTEX_STRUCT = WellKnown.VORTEX_STRUCT;
221+
/// Well-known `fastlanes.bitpacked` id.
222+
WellKnown FASTLANES_BITPACKED = WellKnown.FASTLANES_BITPACKED;
223+
/// Well-known `fastlanes.for` id.
224+
WellKnown FASTLANES_FOR = WellKnown.FASTLANES_FOR;
225+
/// Well-known `fastlanes.delta` id.
226+
WellKnown FASTLANES_DELTA = WellKnown.FASTLANES_DELTA;
227+
/// Well-known `fastlanes.rle` id.
228+
WellKnown FASTLANES_RLE = WellKnown.FASTLANES_RLE;
229+
/// Well-known `vortex.masked` id.
230+
WellKnown VORTEX_MASKED = WellKnown.VORTEX_MASKED;
231+
/// Well-known `vortex.patched` id.
232+
WellKnown VORTEX_PATCHED = WellKnown.VORTEX_PATCHED;
233+
/// Well-known `vortex.variant` id.
234+
WellKnown VORTEX_VARIANT = WellKnown.VORTEX_VARIANT;
113235
}

0 commit comments

Comments
 (0)