11package io .github .dfa1 .vortex .encoding ;
22
33import io .github .dfa1 .vortex .core .VortexException ;
4- import io .github .dfa1 .vortex .core .array .Array ;
5- import io .github .dfa1 .vortex .core .array .ArraySegments ;
6- import io .github .dfa1 .vortex .core .array .UnknownArray ;
74import io .github .dfa1 .vortex .extension .Extension ;
85import io .github .dfa1 .vortex .extension .ExtensionId ;
96
10- import java .lang .foreign .MemorySegment ;
117import java .util .HashMap ;
128import java .util .List ;
139import java .util .Map ;
1410import java .util .ServiceLoader ;
1511
16- /// Registry mapping wire identifiers to their library implementations:
17- /// [Encoding] keyed by [EncodingId], [Extension] keyed by [ExtensionId],
18- /// and [EncodingDecoder] keyed by [EncodingId].
12+ /// Metadata registry for {@link Encoding} descriptors and {@link Extension} implementations.
1913///
20- /// Instances are immutable after construction. Build one via [#builder()] or via the
21- /// [#loadAll()], [#empty()], [#of(List)] convenience factories.
14+ /// <p>Holds only metadata-only {@link Encoding} objects and {@link Extension} impls.
15+ /// Decode dispatch lives in {@code ReadRegistry} (reader module); encode dispatch
16+ /// uses {@code Map<EncodingId, EncodingEncoder>} directly.
17+ ///
18+ /// <p>Instances are immutable after construction. Build one via {@link #builder()} or via the
19+ /// {@link #loadAll()}, {@link #empty()}, {@link #of(List)} convenience factories.
2220public final class Registry {
2321
2422 private final Map <EncodingId , Encoding > encodings ;
2523 private final Map <ExtensionId , Extension > extensions ;
26- private final Map <EncodingId , EncodingDecoder > standaloneDecoders ;
27- private final boolean allowUnknown ;
2824
2925 private Registry (
3026 Map <EncodingId , Encoding > encodings ,
31- Map <ExtensionId , Extension > extensions ,
32- Map <EncodingId , EncodingDecoder > standaloneDecoders ,
33- boolean allowUnknown
27+ Map <ExtensionId , Extension > extensions
3428 ) {
3529 this .encodings = Map .copyOf (encodings );
3630 this .extensions = Map .copyOf (extensions );
37- this .standaloneDecoders = Map .copyOf (standaloneDecoders );
38- this .allowUnknown = allowUnknown ;
3931 }
4032
4133 /// Returns a new {@link Builder}.
@@ -45,7 +37,7 @@ public static Builder builder() {
4537 return new Builder ();
4638 }
4739
48- /// Load all service-loaded [ Encoding]s, [EncodingDecoder]s, and [ Extension] s.
40+ /// Load all service-loaded {@link Encoding}s and {@link Extension} s.
4941 ///
5042 /// @return an immutable {@link Registry} populated with all service-loaded entries
5143 public static Registry loadAll () {
@@ -71,45 +63,12 @@ public static Registry of(List<Encoding> encodings) {
7163 return b .build ();
7264 }
7365
74- /// Recursively wrap a node and its children as [UnknownArray]. Children of an unknown
75- /// parent are always wrapped unknown regardless of whether their own id is recognised —
76- /// matches Rust `decode_foreign` in `vortex-array/src/serde.rs`.
77- private static UnknownArray decodeUnknown (DecodeContext ctx , ArrayNode node ) {
78- String rawId = switch (node ) {
79- case KnownArrayNode k -> k .encodingId ().id ();
80- case UnknownArrayNode u -> u .rawEncodingId ();
81- };
82- MemorySegment [] bufs = new MemorySegment [node .bufferIndices ().length ];
83- for (int i = 0 ; i < bufs .length ; i ++) {
84- bufs [i ] = ctx .buffer (i );
85- }
86- Array [] children = new Array [node .children ().length ];
87- for (int i = 0 ; i < children .length ; i ++) {
88- ArrayNode childNode = node .children ()[i ];
89- DecodeContext childCtx = new DecodeContext (
90- childNode , ctx .dtype (), ctx .rowCount (),
91- ctx .segmentBuffers (), ctx .registry (), ctx .arena ());
92- children [i ] = decodeUnknown (childCtx , childNode );
93- }
94- return new UnknownArray (
95- rawId , ctx .dtype (), ctx .rowCount (),
96- node .metadata (), bufs , children );
97- }
98-
99- /// Returns whether passthrough decode for unknown encoding ids is enabled.
100- ///
101- /// @return {@code true} if unknown encodings are silently wrapped as {@link io.github.dfa1.vortex.core.array.UnknownArray}
102- public boolean isAllowUnknown () {
103- return allowUnknown ;
104- }
105-
106- /// Returns {@code true} if an encoding or decoder is registered for the given id.
66+ /// Returns {@code true} if a descriptor is registered for the given id.
10767 ///
10868 /// @param encodingId the encoding id to query
109- /// @return {@code true} if an {@link Encoding} or {@link EncodingDecoder} is registered
69+ /// @return {@code true} if an {@link Encoding} descriptor is registered
11070 public boolean hasEncoding (EncodingId encodingId ) {
111- return encodings .containsKey (encodingId )
112- || standaloneDecoders .containsKey (encodingId );
71+ return encodings .containsKey (encodingId );
11372 }
11473
11574 /// Returns the registered metadata-only encoding for {@code encodingId}, or {@code null}.
@@ -128,71 +87,17 @@ public Extension lookup(ExtensionId extensionId) {
12887 return extensions .get (extensionId );
12988 }
13089
131- MemorySegment decodeAsSegment (DecodeContext ctx ) {
132- ArrayNode node = ctx .node ();
133- EncodingDecoder decoder = switch (node ) {
134- case KnownArrayNode k -> standaloneDecoders .get (k .encodingId ());
135- case UnknownArrayNode _ -> null ;
136- };
137- if (decoder != null ) {
138- return ArraySegments .of (decoder .decode (ctx ));
139- }
140- String id = switch (node ) {
141- case KnownArrayNode k -> k .encodingId ().id ();
142- case UnknownArrayNode u -> u .rawEncodingId ();
143- };
144- throw new VortexException ("no encoding registered for " + id + " (or encoding has no primary segment)" );
145- }
146-
147- /// Decodes the array described by {@code ctx}.
148- ///
149- /// @param ctx the decode context
150- /// @return the decoded {@link Array}
151- public Array decode (DecodeContext ctx ) {
152- ArrayNode node = ctx .node ();
153- EncodingDecoder decoder = switch (node ) {
154- case KnownArrayNode k -> standaloneDecoders .get (k .encodingId ());
155- case UnknownArrayNode _ -> null ;
156- };
157- if (decoder != null ) {
158- return decoder .decode (ctx );
159- }
160- if (allowUnknown ) {
161- return decodeUnknown (ctx , node );
162- }
163- String id = switch (node ) {
164- case KnownArrayNode k -> k .encodingId ().id ();
165- case UnknownArrayNode u -> u .rawEncodingId ();
166- };
167- throw new VortexException ("no encoding registered for " + id );
168- }
169-
170- /// Builder for [Registry].
90+ /// Builder for {@link Registry}.
17191 ///
172- /// Not thread-safe. Build once, use everywhere — the produced [ Registry] is immutable.
92+ /// Not thread-safe. Build once, use everywhere — the produced {@link Registry} is immutable.
17393 public static final class Builder {
17494
17595 private final Map <EncodingId , Encoding > encodings = new HashMap <>();
17696 private final Map <ExtensionId , Extension > extensions = new HashMap <>();
177- private final Map <EncodingId , EncodingDecoder > standaloneDecoders = new HashMap <>();
178- private boolean allowUnknown = false ;
17997
18098 private Builder () {
18199 }
182100
183- /// Registers a standalone read-only decoder.
184- ///
185- /// @param decoder the {@link EncodingDecoder} to register
186- /// @return this builder, for chaining
187- /// @throws VortexException if a decoder for the same id is already registered
188- public Builder register (EncodingDecoder decoder ) {
189- EncodingDecoder old = standaloneDecoders .put (decoder .encodingId (), decoder );
190- if (old != null ) {
191- throw new VortexException ("encoding decoder %s already registered" .formatted (decoder .encodingId ()));
192- }
193- return this ;
194- }
195-
196101 /// Registers a metadata-only encoding descriptor.
197102 ///
198103 /// @param encoding the {@link Encoding} to register
@@ -219,7 +124,7 @@ public Builder register(Extension extension) {
219124 return this ;
220125 }
221126
222- /// Registers every [ Encoding], [EncodingDecoder], and [ Extension] discovered via
127+ /// Registers every {@link Encoding} and {@link Extension} discovered via
223128 /// {@link ServiceLoader}.
224129 ///
225130 /// @return this builder, for chaining
@@ -231,29 +136,14 @@ public Builder registerServiceLoaded() {
231136 for (Extension extension : ServiceLoader .load (Extension .class )) {
232137 register (extension );
233138 }
234- for (EncodingDecoder decoder : ServiceLoader .load (EncodingDecoder .class )) {
235- register (decoder );
236- }
237- return this ;
238- }
239-
240- /// Enable passthrough decode for unknown encoding ids.
241- ///
242- /// Default is strict: unknown ids throw [VortexException]. When enabled, unknown nodes
243- /// (and all their children, recursively) are wrapped as [UnknownArray] preserving raw
244- /// metadata + buffers + stats. Mirrors Rust `VortexSession::allow_unknown()`.
245- ///
246- /// @return this builder, for chaining
247- public Builder allowUnknown () {
248- this .allowUnknown = true ;
249139 return this ;
250140 }
251141
252- /// Builds an immutable [ Registry] .
142+ /// Builds an immutable {@link Registry} .
253143 ///
254144 /// @return the immutable registry
255145 public Registry build () {
256- return new Registry (encodings , extensions , standaloneDecoders , allowUnknown );
146+ return new Registry (encodings , extensions );
257147 }
258148 }
259149}
0 commit comments