blob: 45389008fd8309f6b21054160c851ac27802236f [file] [log] [blame]
Matthias Andreas Benkardb5d657a2022-02-03 21:14:30 +01001// SPDX-FileCopyrightText: © 2021 Matthias Andreas Benkard <code@mail.matthias.benkard.de>
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01005package eu.mulk.jgvariant.core;
6
7import static java.nio.ByteOrder.LITTLE_ENDIAN;
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +02008import static java.util.Objects.requireNonNullElse;
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +01009import static java.util.stream.Collectors.toMap;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010010
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020011import com.google.errorprone.annotations.Immutable;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010012import java.lang.reflect.InvocationTargetException;
13import java.lang.reflect.RecordComponent;
14import java.nio.ByteBuffer;
15import java.nio.ByteOrder;
16import java.nio.charset.Charset;
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010017import java.text.ParseException;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010018import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.List;
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +010021import java.util.Map;
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +010022import java.util.Map.Entry;
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +010023import java.util.Objects;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010024import java.util.Optional;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010025import java.util.function.Function;
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +010026import java.util.function.Predicate;
27import java.util.function.UnaryOperator;
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010028import org.apiguardian.api.API;
29import org.apiguardian.api.API.Status;
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +010030import org.jetbrains.annotations.NotNull;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010031import org.jetbrains.annotations.Nullable;
32
33/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010034 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010035 *
36 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
37 * the type you wish to decode.
38 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010039 * <p><strong>Example</strong>
40 *
41 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
42 * {@code int}, you can use the following code:
43 *
Matthias Andreas Benkard0239d322022-04-15 20:21:37 +020044 * {@snippet lang="java" :
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010045 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010046 *
47 * var decoder =
48 * Decoder.ofArray(
49 * Decoder.ofStructure(
50 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010051 * Decoder.ofString(UTF_8),
52 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010053 *
Matthias Andreas Benkard0239d322022-04-15 20:21:37 +020054 * byte[] bytes;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010055 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard0239d322022-04-15 20:21:37 +020056 * }
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010057 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010058 * @param <T> the type that the {@link Decoder} can decode.
59 */
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010060@API(status = Status.EXPERIMENTAL)
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +020061@Immutable
62@SuppressWarnings({"ImmutableListOf", "InvalidInlineTag", "java:S1610", "UnescapedEntity"})
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010063public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010064
65 private Decoder() {}
66
67 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010068 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
69 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +010070 * <p><strong>Note:</strong> Due to the way the GVariant serialization format works, it is
71 * important that the start and end boundaries of the passed byte slice correspond to the actual
72 * start and end of the serialized value. The format does generally not allow for the dynamic
73 * discovery of the end of the data structure.
74 *
75 * @param byteSlice a byte slice holding a serialized GVariant.
76 * @return the deserialized value.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010077 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
78 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010079 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010080 */
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +010081 public abstract @NotNull T decode(ByteBuffer byteSlice);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010082
83 abstract byte alignment();
84
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +010085 abstract @Nullable Integer fixedSize();
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010086
87 final boolean hasFixedSize() {
88 return fixedSize() != null;
89 }
90
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010091 /**
92 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
93 *
94 * @param byteOrder the byte order to use.
95 * @return a new, decorated {@link Decoder}.
96 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010097 public final Decoder<T> withByteOrder(ByteOrder byteOrder) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +010098 return new ByteOrderFixingDecoder(byteOrder);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010099 }
100
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100101 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100102 * Creates a new {@link Decoder} from an existing one by applying a function to the result.
103 *
104 * @param function the function to apply.
105 * @return a new, decorated {@link Decoder}.
106 * @see java.util.stream.Stream#map
107 */
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100108 public final <U> Decoder<U> map(Function<@NotNull T, @NotNull U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100109 return new MappingDecoder<>(function);
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100110 }
111
112 /**
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100113 * Creates a new {@link Decoder} from an existing one by applying a function to the input.
114 *
115 * @param function the function to apply.
116 * @return a new, decorated {@link Decoder}.
117 * @see java.util.stream.Stream#map
118 */
119 public final Decoder<T> contramap(UnaryOperator<ByteBuffer> function) {
120 return new ContramappingDecoder(function);
121 }
122
123 /**
124 * Creates a new {@link Decoder} that delegates to one of two other {@link Decoder}s based on a
125 * condition on the input {@link ByteBuffer}.
126 *
127 * @param selector the predicate to use to determine the decoder to use.
128 * @return a new {@link Decoder}.
129 */
130 public static <U> Decoder<U> ofPredicate(
131 Predicate<ByteBuffer> selector, Decoder<U> thenDecoder, Decoder<U> elseDecoder) {
132 return new PredicateDecoder<>(selector, thenDecoder, elseDecoder);
133 }
134
135 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100136 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100137 *
138 * @param elementDecoder a {@link Decoder} for the elements of the array.
139 * @param <U> the element type.
140 * @return a new {@link Decoder}.
141 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100142 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100143 return new ArrayDecoder<>(elementDecoder);
144 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100145
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100146 /**
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100147 * Creates a {@link Decoder} for a {@code Dictionary} type.
148 *
149 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
150 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
151 * @return a new {@link Decoder}.
152 */
153 public static <K, V> Decoder<Map<K, V>> ofDictionary(
154 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
155 return new DictionaryDecoder<>(keyDecoder, valueDecoder);
156 }
157
158 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100159 * Creates a {@link Decoder} for an {@code Array} type of element type {@code byte} into a
160 * primitive {@code byte[]} array.
161 *
162 * @return a new {@link Decoder}.
163 */
164 public static Decoder<byte[]> ofByteArray() {
165 return new ByteArrayDecoder();
166 }
167
168 /**
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100169 * Creates a {@link Decoder} for a {@code Maybe} type.
170 *
171 * @param elementDecoder a {@link Decoder} for the contained element.
172 * @param <U> the element type.
173 * @return a new {@link Decoder}.
174 */
175 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
176 return new MaybeDecoder<>(elementDecoder);
177 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100178
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100179 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100180 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100181 *
182 * @param recordType the {@link Record} type that represents the components of the structure.
183 * @param componentDecoders a {@link Decoder} for each component of the structure.
184 * @param <U> the {@link Record} type that represents the components of the structure.
185 * @return a new {@link Decoder}.
186 */
187 public static <U extends Record> Decoder<U> ofStructure(
188 Class<U> recordType, Decoder<?>... componentDecoders) {
189 return new StructureDecoder<>(recordType, componentDecoders);
190 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100191
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100192 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100193 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
194 *
195 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
196 * more convenient.
197 *
198 * @param componentDecoders a {@link Decoder} for each component of the structure.
199 * @return a new {@link Decoder}.
200 */
201 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
202 return new TupleDecoder(componentDecoders);
203 }
204
205 /**
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100206 * Creates a {@link Decoder} for a {@code Dictionary Entry} type, decoding into a {@link
207 * Map.Entry}.
208 *
209 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
210 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
211 * @return a new {@link Decoder}.
212 */
213 public static <K, V> Decoder<Map.Entry<K, V>> ofDictionaryEntry(
214 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
215 return new DictionaryEntryDecoder<>(keyDecoder, valueDecoder);
216 }
217
218 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100219 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100220 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100221 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100222 *
223 * <ul>
224 * <li>{@link Boolean}
225 * <li>{@link Byte}
226 * <li>{@link Short}
227 * <li>{@link Integer}
228 * <li>{@link Long}
229 * <li>{@link String}
230 * <li>{@link Optional} (a GVariant {@code Maybe} type)
231 * <li>{@link List} (a GVariant array)
Matthias Andreas Benkarda66b73d2021-12-18 19:15:52 +0100232 * <li>{@code Object[]} (a GVariant structure)
Matthias Andreas Benkardd6a25d12021-12-28 01:13:58 +0100233 * <li>{@link java.util.Map} (a dictionary)
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100234 * <li>{@link java.util.Map.Entry} (a dictionary entry)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100235 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100236 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100237 *
238 * @return a new {@link Decoder}.
239 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100240 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100241 return new VariantDecoder();
242 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100243
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100244 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100245 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100246 *
247 * @return a new {@link Decoder}.
248 */
249 public static Decoder<Boolean> ofBoolean() {
250 return new BooleanDecoder();
251 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100252
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100253 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100254 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100255 *
256 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
257 * result of this method.
258 *
259 * @return a new {@link Decoder}.
260 */
261 public static Decoder<Byte> ofByte() {
262 return new ByteDecoder();
263 }
264
265 /**
266 * Creates a {@link Decoder} for the 16-bit {@code short} type.
267 *
268 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
269 * result of this method.
270 *
271 * @return a new {@link Decoder}.
272 */
273 public static Decoder<Short> ofShort() {
274 return new ShortDecoder();
275 }
276
277 /**
278 * Creates a {@link Decoder} for the 32-bit {@code int} type.
279 *
280 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
281 * result of this method.
282 *
283 * @return a new {@link Decoder}.
284 */
285 public static Decoder<Integer> ofInt() {
286 return new IntegerDecoder();
287 }
288
289 /**
290 * Creates a {@link Decoder} for the 64-bit {@code long} type.
291 *
292 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
293 * result of this method.
294 *
295 * @return a new {@link Decoder}.
296 */
297 public static Decoder<Long> ofLong() {
298 return new LongDecoder();
299 }
300
301 /**
302 * Creates a {@link Decoder} for the {@code double} type.
303 *
304 * @return a new {@link Decoder}.
305 */
306 public static Decoder<Double> ofDouble() {
307 return new DoubleDecoder();
308 }
309
310 /**
311 * Creates a {@link Decoder} for the {@link String} type.
312 *
313 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
314 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
315 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +0100316 * @param charset the {@link Charset} the string is encoded in.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100317 * @return a new {@link Decoder}.
318 */
319 public static Decoder<String> ofString(Charset charset) {
320 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100321 }
322
323 private static int align(int offset, byte alignment) {
324 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
325 }
326
327 private static int getIntN(ByteBuffer byteSlice) {
328 var intBytes = new byte[4];
329 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
330 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
331 }
332
333 @SuppressWarnings("java:S3358")
334 private static int byteCount(int n) {
335 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
336 }
337
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100338 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100339
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100340 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100341
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100342 ArrayDecoder(Decoder<U> elementDecoder) {
343 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100344 }
345
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100346 @Override
347 public byte alignment() {
348 return elementDecoder.alignment();
349 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100350
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100351 @Override
352 @Nullable
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100353 public Integer fixedSize() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100354 return null;
355 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100356
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100357 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100358 public @NotNull List<U> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100359 List<U> elements;
360
361 var elementSize = elementDecoder.fixedSize();
362 if (elementSize != null) {
363 // A simple C-style array.
364 elements = new ArrayList<>(byteSlice.limit() / elementSize);
365 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100366 var element = elementDecoder.decode(slicePreservingOrder(byteSlice, i, elementSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100367 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100368 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100369 } else if (byteSlice.limit() == 0) {
370 // A degenerate zero-length array of variable width.
371 elements = List.of();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100372 } else {
373 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100374 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100375 int lastFramingOffset =
376 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
377 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100378
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100379 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100380 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100381 for (int i = 0; i < elementCount; i++) {
382 int framingOffset =
383 getIntN(
384 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100385 elements.add(
386 elementDecoder.decode(
387 slicePreservingOrder(byteSlice, position, framingOffset - position)));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100388 position = align(framingOffset, alignment());
389 }
390 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100391
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100392 return elements;
393 }
394 }
395
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100396 private static class DictionaryDecoder<K, V> extends Decoder<Map<K, V>> {
397
398 private final ArrayDecoder<Map.Entry<K, V>> entryArrayDecoder;
399
400 DictionaryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
401 this.entryArrayDecoder =
402 new ArrayDecoder<>(new DictionaryEntryDecoder<>(keyDecoder, valueDecoder));
403 }
404
405 @Override
406 public byte alignment() {
407 return entryArrayDecoder.alignment();
408 }
409
410 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100411 @Nullable
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100412 public Integer fixedSize() {
413 return entryArrayDecoder.fixedSize();
414 }
415
416 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100417 public @NotNull Map<K, V> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100418 List<Map.Entry<K, V>> entries = entryArrayDecoder.decode(byteSlice);
419 return entries.stream().collect(toMap(Entry::getKey, Entry::getValue));
420 }
421 }
422
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100423 private static class ByteArrayDecoder extends Decoder<byte[]> {
424
425 private static final int ELEMENT_SIZE = 1;
426
427 @Override
428 public byte alignment() {
429 return ELEMENT_SIZE;
430 }
431
432 @Override
433 @Nullable
434 Integer fixedSize() {
435 return null;
436 }
437
438 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100439 public byte @NotNull [] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100440 // A simple C-style array.
441 byte[] elements = new byte[byteSlice.limit() / ELEMENT_SIZE];
442 byteSlice.get(elements);
443 return elements;
444 }
445 }
446
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100447 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
448
449 private final Decoder<U> elementDecoder;
450
451 MaybeDecoder(Decoder<U> elementDecoder) {
452 this.elementDecoder = elementDecoder;
453 }
454
455 @Override
456 public byte alignment() {
457 return elementDecoder.alignment();
458 }
459
460 @Override
461 @Nullable
462 Integer fixedSize() {
463 return null;
464 }
465
466 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100467 public @NotNull Optional<U> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100468 if (!byteSlice.hasRemaining()) {
469 return Optional.empty();
470 } else {
471 if (!elementDecoder.hasFixedSize()) {
472 // Remove trailing zero byte.
473 byteSlice.limit(byteSlice.limit() - 1);
474 }
475
476 return Optional.of(elementDecoder.decode(byteSlice));
477 }
478 }
479 }
480
481 private static class StructureDecoder<U extends Record> extends Decoder<U> {
482
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100483 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100484 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100485
486 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
487 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100488 if (componentDecoders.length != recordComponents.length) {
489 throw new IllegalArgumentException(
490 "number of decoders (%d) does not match number of structure components (%d)"
491 .formatted(componentDecoders.length, recordComponents.length));
492 }
493
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100494 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100495 this.tupleDecoder = new TupleDecoder(componentDecoders);
496 }
497
498 @Override
499 public byte alignment() {
500 return tupleDecoder.alignment();
501 }
502
503 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100504 public @Nullable Integer fixedSize() {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100505 return tupleDecoder.fixedSize();
506 }
507
508 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100509 public @NotNull U decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100510 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
511
512 try {
513 var recordComponentTypes =
514 Arrays.stream(recordType.getRecordComponents())
515 .map(RecordComponent::getType)
516 .toArray(Class<?>[]::new);
517 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
518 return recordConstructor.newInstance(recordConstructorArguments);
519 } catch (NoSuchMethodException
520 | InstantiationException
521 | IllegalAccessException
522 | InvocationTargetException e) {
523 throw new IllegalStateException(e);
524 }
525 }
526 }
527
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200528 @SuppressWarnings("Immutable")
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100529 private static class TupleDecoder extends Decoder<Object[]> {
530
531 private final Decoder<?>[] componentDecoders;
532
533 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100534 this.componentDecoders = componentDecoders;
535 }
536
537 @Override
538 public byte alignment() {
539 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
540 }
541
542 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100543 public @Nullable Integer fixedSize() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100544 int position = 0;
545 for (var componentDecoder : componentDecoders) {
546 var fixedComponentSize = componentDecoder.fixedSize();
547 if (fixedComponentSize == null) {
548 return null;
549 }
550
551 position = align(position, componentDecoder.alignment());
552 position += fixedComponentSize;
553 }
554
555 if (position == 0) {
556 return 1;
557 }
558
559 return align(position, alignment());
560 }
561
562 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100563 public Object @NotNull [] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100564 int framingOffsetSize = byteCount(byteSlice.limit());
565
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100566 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100567
568 int position = 0;
569 int framingOffsetIndex = 0;
570 int componentIndex = 0;
571 for (var componentDecoder : componentDecoders) {
572 position = align(position, componentDecoder.alignment());
573
574 var fixedComponentSize = componentDecoder.fixedSize();
575 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100576 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100577 componentDecoder.decode(
578 slicePreservingOrder(byteSlice, position, fixedComponentSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100579 position += fixedComponentSize;
580 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100581 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100582 // The last component never has a framing offset.
583 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100584 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100585 componentDecoder.decode(
586 slicePreservingOrder(byteSlice, position, endPosition - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100587 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100588 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100589 int framingOffset =
590 getIntN(
591 byteSlice.slice(
592 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
593 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100594 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100595 componentDecoder.decode(
596 slicePreservingOrder(byteSlice, position, framingOffset - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100597 position = framingOffset;
598 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100599 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100600 }
601
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100602 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100603 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100604
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100605 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100606 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100607 }
608
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100609 private static class DictionaryEntryDecoder<K, V> extends Decoder<Map.Entry<K, V>> {
610
611 private final TupleDecoder tupleDecoder;
612
613 DictionaryEntryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
614 this.tupleDecoder = new TupleDecoder(keyDecoder, valueDecoder);
615 }
616
617 @Override
618 public byte alignment() {
619 return tupleDecoder.alignment();
620 }
621
622 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100623 public @Nullable Integer fixedSize() {
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100624 return tupleDecoder.fixedSize();
625 }
626
627 @Override
628 @SuppressWarnings("unchecked")
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100629 public Map.@NotNull Entry<K, V> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100630 Object[] components = tupleDecoder.decode(byteSlice);
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200631 return Map.entry((K) components[0], (V) components[1]);
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100632 }
633 }
634
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100635 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100636
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100637 @Override
638 public byte alignment() {
639 return 8;
640 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100641
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100642 @Override
643 @Nullable
644 Integer fixedSize() {
645 return null;
646 }
647
648 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100649 public @NotNull Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100650 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
651 if (byteSlice.get(i) != 0) {
652 continue;
653 }
654
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100655 var dataBytes = slicePreservingOrder(byteSlice, 0, i);
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100656 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100657
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100658 Signature signature;
659 try {
660 signature = Signature.parse(signatureBytes);
661 } catch (ParseException e) {
662 throw new IllegalArgumentException(e);
663 }
664
665 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100666 }
667
668 throw new IllegalArgumentException("variant signature not found");
669 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100670 }
671
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100672 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100673
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100674 @Override
675 public byte alignment() {
676 return 1;
677 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100678
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100679 @Override
680 public Integer fixedSize() {
681 return 1;
682 }
683
684 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100685 public @NotNull Boolean decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100686 return byteSlice.get() != 0;
687 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100688 }
689
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100690 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100691
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100692 @Override
693 public byte alignment() {
694 return 1;
695 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100696
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100697 @Override
698 public Integer fixedSize() {
699 return 1;
700 }
701
702 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100703 public @NotNull Byte decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100704 return byteSlice.get();
705 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100706 }
707
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100708 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100709
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100710 @Override
711 public byte alignment() {
712 return 2;
713 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100714
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100715 @Override
716 public Integer fixedSize() {
717 return 2;
718 }
719
720 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100721 public @NotNull Short decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100722 return byteSlice.getShort();
723 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100724 }
725
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100726 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100727
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100728 @Override
729 public byte alignment() {
730 return 4;
731 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100732
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100733 @Override
734 public Integer fixedSize() {
735 return 4;
736 }
737
738 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100739 public @NotNull Integer decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100740 return byteSlice.getInt();
741 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100742 }
743
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100744 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100745
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100746 @Override
747 public byte alignment() {
748 return 8;
749 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100750
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100751 @Override
752 public Integer fixedSize() {
753 return 8;
754 }
755
756 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100757 public @NotNull Long decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100758 return byteSlice.getLong();
759 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100760 }
761
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100762 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100763
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100764 @Override
765 public byte alignment() {
766 return 8;
767 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100768
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100769 @Override
770 public Integer fixedSize() {
771 return 8;
772 }
773
774 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100775 public @NotNull Double decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100776 return byteSlice.getDouble();
777 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100778 }
779
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100780 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100781
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100782 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100783
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100784 public StringDecoder(Charset charset) {
785 this.charset = charset;
786 }
787
788 @Override
789 public byte alignment() {
790 return 1;
791 }
792
793 @Override
794 @Nullable
795 Integer fixedSize() {
796 return null;
797 }
798
799 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100800 public @NotNull String decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100801 byteSlice.limit(byteSlice.limit() - 1);
802 return charset.decode(byteSlice).toString();
803 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100804 }
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100805
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200806 @SuppressWarnings("Immutable")
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100807 private class MappingDecoder<U> extends Decoder<U> {
808
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100809 private final Function<@NotNull T, @NotNull U> function;
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100810
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100811 MappingDecoder(Function<@NotNull T, @NotNull U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100812 this.function = function;
813 }
814
815 @Override
816 public byte alignment() {
817 return Decoder.this.alignment();
818 }
819
820 @Override
821 public @Nullable Integer fixedSize() {
822 return Decoder.this.fixedSize();
823 }
824
825 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100826 public @NotNull U decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100827 return function.apply(Decoder.this.decode(byteSlice));
828 }
829 }
830
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200831 @SuppressWarnings("Immutable")
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100832 private class ContramappingDecoder extends Decoder<T> {
833
834 private final UnaryOperator<ByteBuffer> function;
835
836 ContramappingDecoder(UnaryOperator<ByteBuffer> function) {
837 this.function = function;
838 }
839
840 @Override
841 public byte alignment() {
842 return Decoder.this.alignment();
843 }
844
845 @Override
846 public @Nullable Integer fixedSize() {
847 return Decoder.this.fixedSize();
848 }
849
850 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100851 public @NotNull T decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100852 var transformedBuffer = function.apply(byteSlice.asReadOnlyBuffer().order(byteSlice.order()));
853 return Decoder.this.decode(transformedBuffer);
854 }
855 }
856
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100857 private class ByteOrderFixingDecoder extends Decoder<T> {
858
859 private final ByteOrder byteOrder;
860
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100861 ByteOrderFixingDecoder(ByteOrder byteOrder) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100862 this.byteOrder = byteOrder;
863 }
864
865 @Override
866 public byte alignment() {
867 return Decoder.this.alignment();
868 }
869
870 @Override
871 public @Nullable Integer fixedSize() {
872 return Decoder.this.fixedSize();
873 }
874
875 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100876 public @NotNull T decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100877 var newByteSlice = byteSlice.duplicate();
878 newByteSlice.order(byteOrder);
879 return Decoder.this.decode(newByteSlice);
880 }
881 }
882
883 private static ByteBuffer slicePreservingOrder(ByteBuffer byteSlice, int index, int length) {
884 return byteSlice.slice(index, length).order(byteSlice.order());
885 }
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100886
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200887 @SuppressWarnings("Immutable")
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100888 private static class PredicateDecoder<U> extends Decoder<U> {
889
890 private final Predicate<ByteBuffer> selector;
891 private final Decoder<U> thenDecoder;
892 private final Decoder<U> elseDecoder;
893
894 PredicateDecoder(
895 Predicate<ByteBuffer> selector, Decoder<U> thenDecoder, Decoder<U> elseDecoder) {
896 this.selector = selector;
897 this.thenDecoder = thenDecoder;
898 this.elseDecoder = elseDecoder;
899 if (thenDecoder.alignment() != elseDecoder.alignment()) {
900 throw new IllegalArgumentException(
901 "incompatible alignments in predicate branches: then=%d, else=%d"
902 .formatted(thenDecoder.alignment(), elseDecoder.alignment()));
903 }
904
905 if (!Objects.equals(thenDecoder.fixedSize(), elseDecoder.fixedSize())) {
906 throw new IllegalArgumentException(
907 "incompatible sizes in predicate branches: then=%s, else=%s"
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100908 .formatted(
Matthias Andreas Benkard91dbd742022-10-17 19:38:56 +0200909 requireNonNullElse(thenDecoder.fixedSize(), "(null)"),
910 requireNonNullElse(elseDecoder.fixedSize(), "(null)")));
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100911 }
912 }
913
914 @Override
915 public byte alignment() {
916 return thenDecoder.alignment();
917 }
918
919 @Override
920 public @Nullable Integer fixedSize() {
921 return thenDecoder.fixedSize();
922 }
923
924 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100925 public @NotNull U decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100926 var b = selector.test(byteSlice);
927 byteSlice.rewind();
928 return b ? thenDecoder.decode(byteSlice) : elseDecoder.decode(byteSlice);
929 }
930 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100931}