blob: 8297d79e49bbaf0d97df23e97cbe5cdd509f7448 [file] [log] [blame]
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01001package eu.mulk.jgvariant.core;
2
3import static java.nio.ByteOrder.LITTLE_ENDIAN;
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +01004import static java.util.stream.Collectors.toMap;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01005
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01006import java.lang.reflect.InvocationTargetException;
7import java.lang.reflect.RecordComponent;
8import java.nio.ByteBuffer;
9import java.nio.ByteOrder;
10import java.nio.charset.Charset;
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010011import java.text.ParseException;
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +010012import java.util.AbstractMap.SimpleImmutableEntry;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010013import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.List;
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +010016import java.util.Map;
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +010017import java.util.Map.Entry;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010018import java.util.Optional;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010019import java.util.function.Function;
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010020import org.apiguardian.api.API;
21import org.apiguardian.api.API.Status;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010022import org.jetbrains.annotations.Nullable;
23
24/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010025 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010026 *
27 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
28 * the type you wish to decode.
29 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010030 * <p><strong>Example</strong>
31 *
32 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
33 * {@code int}, you can use the following code:
34 *
35 * <pre>{@code
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010036 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010037 *
38 * var decoder =
39 * Decoder.ofArray(
40 * Decoder.ofStructure(
41 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010042 * Decoder.ofString(UTF_8),
43 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010044 *
45 * byte[] bytes = ...;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010046 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010047 * }</pre>
48 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010049 * @param <T> the type that the {@link Decoder} can decode.
50 */
51@SuppressWarnings("java:S1610")
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010052@API(status = Status.EXPERIMENTAL)
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010053public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010054
55 private Decoder() {}
56
57 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010058 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
59 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +010060 * <p><strong>Note:</strong> Due to the way the GVariant serialization format works, it is
61 * important that the start and end boundaries of the passed byte slice correspond to the actual
62 * start and end of the serialized value. The format does generally not allow for the dynamic
63 * discovery of the end of the data structure.
64 *
65 * @param byteSlice a byte slice holding a serialized GVariant.
66 * @return the deserialized value.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010067 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
68 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010069 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010070 */
71 public abstract T decode(ByteBuffer byteSlice);
72
73 abstract byte alignment();
74
75 @Nullable
76 abstract Integer fixedSize();
77
78 final boolean hasFixedSize() {
79 return fixedSize() != null;
80 }
81
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010082 /**
83 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
84 *
85 * @param byteOrder the byte order to use.
86 * @return a new, decorated {@link Decoder}.
87 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010088 public final Decoder<T> withByteOrder(ByteOrder byteOrder) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +010089 return new ByteOrderFixingDecoder(byteOrder);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010090 }
91
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010092 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010093 * Creates a new {@link Decoder} from an existing one by applying a function to the result.
94 *
95 * @param function the function to apply.
96 * @return a new, decorated {@link Decoder}.
97 * @see java.util.stream.Stream#map
98 */
99 public final <U> Decoder<U> map(Function<T, U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100100 return new MappingDecoder<>(function);
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100101 }
102
103 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100104 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100105 *
106 * @param elementDecoder a {@link Decoder} for the elements of the array.
107 * @param <U> the element type.
108 * @return a new {@link Decoder}.
109 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100110 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100111 return new ArrayDecoder<>(elementDecoder);
112 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100113
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100114 /**
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100115 * Creates a {@link Decoder} for a {@code Dictionary} type.
116 *
117 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
118 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
119 * @return a new {@link Decoder}.
120 */
121 public static <K, V> Decoder<Map<K, V>> ofDictionary(
122 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
123 return new DictionaryDecoder<>(keyDecoder, valueDecoder);
124 }
125
126 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100127 * Creates a {@link Decoder} for an {@code Array} type of element type {@code byte} into a
128 * primitive {@code byte[]} array.
129 *
130 * @return a new {@link Decoder}.
131 */
132 public static Decoder<byte[]> ofByteArray() {
133 return new ByteArrayDecoder();
134 }
135
136 /**
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100137 * Creates a {@link Decoder} for a {@code Maybe} type.
138 *
139 * @param elementDecoder a {@link Decoder} for the contained element.
140 * @param <U> the element type.
141 * @return a new {@link Decoder}.
142 */
143 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
144 return new MaybeDecoder<>(elementDecoder);
145 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100146
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100147 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100148 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100149 *
150 * @param recordType the {@link Record} type that represents the components of the structure.
151 * @param componentDecoders a {@link Decoder} for each component of the structure.
152 * @param <U> the {@link Record} type that represents the components of the structure.
153 * @return a new {@link Decoder}.
154 */
155 public static <U extends Record> Decoder<U> ofStructure(
156 Class<U> recordType, Decoder<?>... componentDecoders) {
157 return new StructureDecoder<>(recordType, componentDecoders);
158 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100159
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100160 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100161 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
162 *
163 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
164 * more convenient.
165 *
166 * @param componentDecoders a {@link Decoder} for each component of the structure.
167 * @return a new {@link Decoder}.
168 */
169 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
170 return new TupleDecoder(componentDecoders);
171 }
172
173 /**
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100174 * Creates a {@link Decoder} for a {@code Dictionary Entry} type, decoding into a {@link
175 * Map.Entry}.
176 *
177 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
178 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
179 * @return a new {@link Decoder}.
180 */
181 public static <K, V> Decoder<Map.Entry<K, V>> ofDictionaryEntry(
182 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
183 return new DictionaryEntryDecoder<>(keyDecoder, valueDecoder);
184 }
185
186 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100187 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100188 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100189 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100190 *
191 * <ul>
192 * <li>{@link Boolean}
193 * <li>{@link Byte}
194 * <li>{@link Short}
195 * <li>{@link Integer}
196 * <li>{@link Long}
197 * <li>{@link String}
198 * <li>{@link Optional} (a GVariant {@code Maybe} type)
199 * <li>{@link List} (a GVariant array)
Matthias Andreas Benkarda66b73d2021-12-18 19:15:52 +0100200 * <li>{@code Object[]} (a GVariant structure)
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100201 * <li>{@link java.util.Map.Entry} (a dictionary entry)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100202 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100203 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100204 *
205 * @return a new {@link Decoder}.
206 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100207 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100208 return new VariantDecoder();
209 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100210
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100211 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100212 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100213 *
214 * @return a new {@link Decoder}.
215 */
216 public static Decoder<Boolean> ofBoolean() {
217 return new BooleanDecoder();
218 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100219
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100220 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100221 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100222 *
223 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
224 * result of this method.
225 *
226 * @return a new {@link Decoder}.
227 */
228 public static Decoder<Byte> ofByte() {
229 return new ByteDecoder();
230 }
231
232 /**
233 * Creates a {@link Decoder} for the 16-bit {@code short} type.
234 *
235 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
236 * result of this method.
237 *
238 * @return a new {@link Decoder}.
239 */
240 public static Decoder<Short> ofShort() {
241 return new ShortDecoder();
242 }
243
244 /**
245 * Creates a {@link Decoder} for the 32-bit {@code int} type.
246 *
247 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
248 * result of this method.
249 *
250 * @return a new {@link Decoder}.
251 */
252 public static Decoder<Integer> ofInt() {
253 return new IntegerDecoder();
254 }
255
256 /**
257 * Creates a {@link Decoder} for the 64-bit {@code long} type.
258 *
259 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
260 * result of this method.
261 *
262 * @return a new {@link Decoder}.
263 */
264 public static Decoder<Long> ofLong() {
265 return new LongDecoder();
266 }
267
268 /**
269 * Creates a {@link Decoder} for the {@code double} type.
270 *
271 * @return a new {@link Decoder}.
272 */
273 public static Decoder<Double> ofDouble() {
274 return new DoubleDecoder();
275 }
276
277 /**
278 * Creates a {@link Decoder} for the {@link String} type.
279 *
280 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
281 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
282 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +0100283 * @param charset the {@link Charset} the string is encoded in.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100284 * @return a new {@link Decoder}.
285 */
286 public static Decoder<String> ofString(Charset charset) {
287 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100288 }
289
290 private static int align(int offset, byte alignment) {
291 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
292 }
293
294 private static int getIntN(ByteBuffer byteSlice) {
295 var intBytes = new byte[4];
296 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
297 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
298 }
299
300 @SuppressWarnings("java:S3358")
301 private static int byteCount(int n) {
302 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
303 }
304
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100305 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100306
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100307 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100308
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100309 ArrayDecoder(Decoder<U> elementDecoder) {
310 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100311 }
312
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100313 @Override
314 public byte alignment() {
315 return elementDecoder.alignment();
316 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100317
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100318 @Override
319 @Nullable
320 Integer fixedSize() {
321 return null;
322 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100323
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100324 @Override
325 public List<U> decode(ByteBuffer byteSlice) {
326 List<U> elements;
327
328 var elementSize = elementDecoder.fixedSize();
329 if (elementSize != null) {
330 // A simple C-style array.
331 elements = new ArrayList<>(byteSlice.limit() / elementSize);
332 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100333 var element = elementDecoder.decode(slicePreservingOrder(byteSlice, i, elementSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100334 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100335 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100336 } else if (byteSlice.limit() == 0) {
337 // A degenerate zero-length array of variable width.
338 elements = List.of();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100339 } else {
340 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100341 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100342 int lastFramingOffset =
343 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
344 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100345
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100346 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100347 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100348 for (int i = 0; i < elementCount; i++) {
349 int framingOffset =
350 getIntN(
351 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100352 elements.add(
353 elementDecoder.decode(
354 slicePreservingOrder(byteSlice, position, framingOffset - position)));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100355 position = align(framingOffset, alignment());
356 }
357 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100358
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100359 return elements;
360 }
361 }
362
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100363 private static class DictionaryDecoder<K, V> extends Decoder<Map<K, V>> {
364
365 private final ArrayDecoder<Map.Entry<K, V>> entryArrayDecoder;
366
367 DictionaryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
368 this.entryArrayDecoder =
369 new ArrayDecoder<>(new DictionaryEntryDecoder<>(keyDecoder, valueDecoder));
370 }
371
372 @Override
373 public byte alignment() {
374 return entryArrayDecoder.alignment();
375 }
376
377 @Override
378 public Integer fixedSize() {
379 return entryArrayDecoder.fixedSize();
380 }
381
382 @Override
383 public Map<K, V> decode(ByteBuffer byteSlice) {
384 List<Map.Entry<K, V>> entries = entryArrayDecoder.decode(byteSlice);
385 return entries.stream().collect(toMap(Entry::getKey, Entry::getValue));
386 }
387 }
388
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100389 private static class ByteArrayDecoder extends Decoder<byte[]> {
390
391 private static final int ELEMENT_SIZE = 1;
392
393 @Override
394 public byte alignment() {
395 return ELEMENT_SIZE;
396 }
397
398 @Override
399 @Nullable
400 Integer fixedSize() {
401 return null;
402 }
403
404 @Override
405 public byte[] decode(ByteBuffer byteSlice) {
406 // A simple C-style array.
407 byte[] elements = new byte[byteSlice.limit() / ELEMENT_SIZE];
408 byteSlice.get(elements);
409 return elements;
410 }
411 }
412
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100413 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
414
415 private final Decoder<U> elementDecoder;
416
417 MaybeDecoder(Decoder<U> elementDecoder) {
418 this.elementDecoder = elementDecoder;
419 }
420
421 @Override
422 public byte alignment() {
423 return elementDecoder.alignment();
424 }
425
426 @Override
427 @Nullable
428 Integer fixedSize() {
429 return null;
430 }
431
432 @Override
433 public Optional<U> decode(ByteBuffer byteSlice) {
434 if (!byteSlice.hasRemaining()) {
435 return Optional.empty();
436 } else {
437 if (!elementDecoder.hasFixedSize()) {
438 // Remove trailing zero byte.
439 byteSlice.limit(byteSlice.limit() - 1);
440 }
441
442 return Optional.of(elementDecoder.decode(byteSlice));
443 }
444 }
445 }
446
447 private static class StructureDecoder<U extends Record> extends Decoder<U> {
448
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100449 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100450 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100451
452 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
453 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100454 if (componentDecoders.length != recordComponents.length) {
455 throw new IllegalArgumentException(
456 "number of decoders (%d) does not match number of structure components (%d)"
457 .formatted(componentDecoders.length, recordComponents.length));
458 }
459
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100460 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100461 this.tupleDecoder = new TupleDecoder(componentDecoders);
462 }
463
464 @Override
465 public byte alignment() {
466 return tupleDecoder.alignment();
467 }
468
469 @Override
470 public Integer fixedSize() {
471 return tupleDecoder.fixedSize();
472 }
473
474 @Override
475 public U decode(ByteBuffer byteSlice) {
476 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
477
478 try {
479 var recordComponentTypes =
480 Arrays.stream(recordType.getRecordComponents())
481 .map(RecordComponent::getType)
482 .toArray(Class<?>[]::new);
483 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
484 return recordConstructor.newInstance(recordConstructorArguments);
485 } catch (NoSuchMethodException
486 | InstantiationException
487 | IllegalAccessException
488 | InvocationTargetException e) {
489 throw new IllegalStateException(e);
490 }
491 }
492 }
493
494 private static class TupleDecoder extends Decoder<Object[]> {
495
496 private final Decoder<?>[] componentDecoders;
497
498 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100499 this.componentDecoders = componentDecoders;
500 }
501
502 @Override
503 public byte alignment() {
504 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
505 }
506
507 @Override
508 public Integer fixedSize() {
509 int position = 0;
510 for (var componentDecoder : componentDecoders) {
511 var fixedComponentSize = componentDecoder.fixedSize();
512 if (fixedComponentSize == null) {
513 return null;
514 }
515
516 position = align(position, componentDecoder.alignment());
517 position += fixedComponentSize;
518 }
519
520 if (position == 0) {
521 return 1;
522 }
523
524 return align(position, alignment());
525 }
526
527 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100528 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100529 int framingOffsetSize = byteCount(byteSlice.limit());
530
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100531 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100532
533 int position = 0;
534 int framingOffsetIndex = 0;
535 int componentIndex = 0;
536 for (var componentDecoder : componentDecoders) {
537 position = align(position, componentDecoder.alignment());
538
539 var fixedComponentSize = componentDecoder.fixedSize();
540 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100541 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100542 componentDecoder.decode(
543 slicePreservingOrder(byteSlice, position, fixedComponentSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100544 position += fixedComponentSize;
545 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100546 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100547 // The last component never has a framing offset.
548 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100549 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100550 componentDecoder.decode(
551 slicePreservingOrder(byteSlice, position, endPosition - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100552 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100553 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100554 int framingOffset =
555 getIntN(
556 byteSlice.slice(
557 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
558 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100559 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100560 componentDecoder.decode(
561 slicePreservingOrder(byteSlice, position, framingOffset - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100562 position = framingOffset;
563 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100564 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100565 }
566
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100567 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100568 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100569
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100570 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100571 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100572 }
573
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100574 private static class DictionaryEntryDecoder<K, V> extends Decoder<Map.Entry<K, V>> {
575
576 private final TupleDecoder tupleDecoder;
577
578 DictionaryEntryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
579 this.tupleDecoder = new TupleDecoder(keyDecoder, valueDecoder);
580 }
581
582 @Override
583 public byte alignment() {
584 return tupleDecoder.alignment();
585 }
586
587 @Override
588 public Integer fixedSize() {
589 return tupleDecoder.fixedSize();
590 }
591
592 @Override
593 @SuppressWarnings("unchecked")
594 public Map.Entry<K, V> decode(ByteBuffer byteSlice) {
595 Object[] components = tupleDecoder.decode(byteSlice);
596 return new SimpleImmutableEntry<>((K) components[0], (V) components[1]);
597 }
598 }
599
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100600 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100601
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100602 @Override
603 public byte alignment() {
604 return 8;
605 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100606
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100607 @Override
608 @Nullable
609 Integer fixedSize() {
610 return null;
611 }
612
613 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100614 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100615 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
616 if (byteSlice.get(i) != 0) {
617 continue;
618 }
619
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100620 var dataBytes = slicePreservingOrder(byteSlice, 0, i);
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100621 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100622
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100623 Signature signature;
624 try {
625 signature = Signature.parse(signatureBytes);
626 } catch (ParseException e) {
627 throw new IllegalArgumentException(e);
628 }
629
630 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100631 }
632
633 throw new IllegalArgumentException("variant signature not found");
634 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100635 }
636
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100637 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100638
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100639 @Override
640 public byte alignment() {
641 return 1;
642 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100643
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100644 @Override
645 public Integer fixedSize() {
646 return 1;
647 }
648
649 @Override
650 public Boolean decode(ByteBuffer byteSlice) {
651 return byteSlice.get() != 0;
652 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100653 }
654
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100655 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100656
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100657 @Override
658 public byte alignment() {
659 return 1;
660 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100661
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100662 @Override
663 public Integer fixedSize() {
664 return 1;
665 }
666
667 @Override
668 public Byte decode(ByteBuffer byteSlice) {
669 return byteSlice.get();
670 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100671 }
672
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100673 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100674
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100675 @Override
676 public byte alignment() {
677 return 2;
678 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100679
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100680 @Override
681 public Integer fixedSize() {
682 return 2;
683 }
684
685 @Override
686 public Short decode(ByteBuffer byteSlice) {
687 return byteSlice.getShort();
688 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100689 }
690
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100691 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100692
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100693 @Override
694 public byte alignment() {
695 return 4;
696 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100697
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100698 @Override
699 public Integer fixedSize() {
700 return 4;
701 }
702
703 @Override
704 public Integer decode(ByteBuffer byteSlice) {
705 return byteSlice.getInt();
706 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100707 }
708
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100709 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100710
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100711 @Override
712 public byte alignment() {
713 return 8;
714 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100715
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100716 @Override
717 public Integer fixedSize() {
718 return 8;
719 }
720
721 @Override
722 public Long decode(ByteBuffer byteSlice) {
723 return byteSlice.getLong();
724 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100725 }
726
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100727 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100728
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100729 @Override
730 public byte alignment() {
731 return 8;
732 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100733
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100734 @Override
735 public Integer fixedSize() {
736 return 8;
737 }
738
739 @Override
740 public Double decode(ByteBuffer byteSlice) {
741 return byteSlice.getDouble();
742 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100743 }
744
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100745 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100746
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100747 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100748
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100749 public StringDecoder(Charset charset) {
750 this.charset = charset;
751 }
752
753 @Override
754 public byte alignment() {
755 return 1;
756 }
757
758 @Override
759 @Nullable
760 Integer fixedSize() {
761 return null;
762 }
763
764 @Override
765 public String decode(ByteBuffer byteSlice) {
766 byteSlice.limit(byteSlice.limit() - 1);
767 return charset.decode(byteSlice).toString();
768 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100769 }
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100770
771 private class MappingDecoder<U> extends Decoder<U> {
772
773 private final Function<T, U> function;
774
775 public MappingDecoder(Function<T, U> function) {
776 this.function = function;
777 }
778
779 @Override
780 public byte alignment() {
781 return Decoder.this.alignment();
782 }
783
784 @Override
785 public @Nullable Integer fixedSize() {
786 return Decoder.this.fixedSize();
787 }
788
789 @Override
790 public U decode(ByteBuffer byteSlice) {
791 return function.apply(Decoder.this.decode(byteSlice));
792 }
793 }
794
795 private class ByteOrderFixingDecoder extends Decoder<T> {
796
797 private final ByteOrder byteOrder;
798
799 public ByteOrderFixingDecoder(ByteOrder byteOrder) {
800 this.byteOrder = byteOrder;
801 }
802
803 @Override
804 public byte alignment() {
805 return Decoder.this.alignment();
806 }
807
808 @Override
809 public @Nullable Integer fixedSize() {
810 return Decoder.this.fixedSize();
811 }
812
813 @Override
814 public T decode(ByteBuffer byteSlice) {
815 var newByteSlice = byteSlice.duplicate();
816 newByteSlice.order(byteOrder);
817 return Decoder.this.decode(newByteSlice);
818 }
819 }
820
821 private static ByteBuffer slicePreservingOrder(ByteBuffer byteSlice, int index, int length) {
822 return byteSlice.slice(index, length).order(byteSlice.order());
823 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100824}