blob: 8a3741ba07e86d567e388c853ec8dceda461d337 [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 Benkard9a6c8ed2021-12-28 01:00:22 +01008import static java.util.stream.Collectors.toMap;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01009
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010010import java.lang.reflect.InvocationTargetException;
11import java.lang.reflect.RecordComponent;
12import java.nio.ByteBuffer;
13import java.nio.ByteOrder;
14import java.nio.charset.Charset;
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010015import java.text.ParseException;
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +010016import java.util.AbstractMap.SimpleImmutableEntry;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010017import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.List;
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +010020import java.util.Map;
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +010021import java.util.Map.Entry;
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +010022import java.util.Objects;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010023import java.util.Optional;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010024import java.util.function.Function;
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +010025import java.util.function.Predicate;
26import java.util.function.UnaryOperator;
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010027import org.apiguardian.api.API;
28import org.apiguardian.api.API.Status;
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +010029import org.jetbrains.annotations.NotNull;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010030import org.jetbrains.annotations.Nullable;
31
32/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010033 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010034 *
35 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
36 * the type you wish to decode.
37 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010038 * <p><strong>Example</strong>
39 *
40 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
41 * {@code int}, you can use the following code:
42 *
43 * <pre>{@code
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010044 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010045 *
46 * var decoder =
47 * Decoder.ofArray(
48 * Decoder.ofStructure(
49 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010050 * Decoder.ofString(UTF_8),
51 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010052 *
53 * byte[] bytes = ...;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010054 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010055 * }</pre>
56 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010057 * @param <T> the type that the {@link Decoder} can decode.
58 */
59@SuppressWarnings("java:S1610")
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010060@API(status = Status.EXPERIMENTAL)
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010061public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010062
63 private Decoder() {}
64
65 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010066 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
67 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +010068 * <p><strong>Note:</strong> Due to the way the GVariant serialization format works, it is
69 * important that the start and end boundaries of the passed byte slice correspond to the actual
70 * start and end of the serialized value. The format does generally not allow for the dynamic
71 * discovery of the end of the data structure.
72 *
73 * @param byteSlice a byte slice holding a serialized GVariant.
74 * @return the deserialized value.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010075 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
76 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010077 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010078 */
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +010079 public abstract @NotNull T decode(ByteBuffer byteSlice);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010080
81 abstract byte alignment();
82
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +010083 abstract @Nullable Integer fixedSize();
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010084
85 final boolean hasFixedSize() {
86 return fixedSize() != null;
87 }
88
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010089 /**
90 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
91 *
92 * @param byteOrder the byte order to use.
93 * @return a new, decorated {@link Decoder}.
94 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010095 public final Decoder<T> withByteOrder(ByteOrder byteOrder) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +010096 return new ByteOrderFixingDecoder(byteOrder);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010097 }
98
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010099 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100100 * Creates a new {@link Decoder} from an existing one by applying a function to the result.
101 *
102 * @param function the function to apply.
103 * @return a new, decorated {@link Decoder}.
104 * @see java.util.stream.Stream#map
105 */
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100106 public final <U> Decoder<U> map(Function<@NotNull T, @NotNull U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100107 return new MappingDecoder<>(function);
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100108 }
109
110 /**
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100111 * Creates a new {@link Decoder} from an existing one by applying a function to the input.
112 *
113 * @param function the function to apply.
114 * @return a new, decorated {@link Decoder}.
115 * @see java.util.stream.Stream#map
116 */
117 public final Decoder<T> contramap(UnaryOperator<ByteBuffer> function) {
118 return new ContramappingDecoder(function);
119 }
120
121 /**
122 * Creates a new {@link Decoder} that delegates to one of two other {@link Decoder}s based on a
123 * condition on the input {@link ByteBuffer}.
124 *
125 * @param selector the predicate to use to determine the decoder to use.
126 * @return a new {@link Decoder}.
127 */
128 public static <U> Decoder<U> ofPredicate(
129 Predicate<ByteBuffer> selector, Decoder<U> thenDecoder, Decoder<U> elseDecoder) {
130 return new PredicateDecoder<>(selector, thenDecoder, elseDecoder);
131 }
132
133 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100134 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100135 *
136 * @param elementDecoder a {@link Decoder} for the elements of the array.
137 * @param <U> the element type.
138 * @return a new {@link Decoder}.
139 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100140 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100141 return new ArrayDecoder<>(elementDecoder);
142 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100143
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100144 /**
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100145 * Creates a {@link Decoder} for a {@code Dictionary} type.
146 *
147 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
148 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
149 * @return a new {@link Decoder}.
150 */
151 public static <K, V> Decoder<Map<K, V>> ofDictionary(
152 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
153 return new DictionaryDecoder<>(keyDecoder, valueDecoder);
154 }
155
156 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100157 * Creates a {@link Decoder} for an {@code Array} type of element type {@code byte} into a
158 * primitive {@code byte[]} array.
159 *
160 * @return a new {@link Decoder}.
161 */
162 public static Decoder<byte[]> ofByteArray() {
163 return new ByteArrayDecoder();
164 }
165
166 /**
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100167 * Creates a {@link Decoder} for a {@code Maybe} type.
168 *
169 * @param elementDecoder a {@link Decoder} for the contained element.
170 * @param <U> the element type.
171 * @return a new {@link Decoder}.
172 */
173 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
174 return new MaybeDecoder<>(elementDecoder);
175 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100176
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100177 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100178 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100179 *
180 * @param recordType the {@link Record} type that represents the components of the structure.
181 * @param componentDecoders a {@link Decoder} for each component of the structure.
182 * @param <U> the {@link Record} type that represents the components of the structure.
183 * @return a new {@link Decoder}.
184 */
185 public static <U extends Record> Decoder<U> ofStructure(
186 Class<U> recordType, Decoder<?>... componentDecoders) {
187 return new StructureDecoder<>(recordType, componentDecoders);
188 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100189
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100190 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100191 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
192 *
193 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
194 * more convenient.
195 *
196 * @param componentDecoders a {@link Decoder} for each component of the structure.
197 * @return a new {@link Decoder}.
198 */
199 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
200 return new TupleDecoder(componentDecoders);
201 }
202
203 /**
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100204 * Creates a {@link Decoder} for a {@code Dictionary Entry} type, decoding into a {@link
205 * Map.Entry}.
206 *
207 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
208 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
209 * @return a new {@link Decoder}.
210 */
211 public static <K, V> Decoder<Map.Entry<K, V>> ofDictionaryEntry(
212 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
213 return new DictionaryEntryDecoder<>(keyDecoder, valueDecoder);
214 }
215
216 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100217 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100218 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100219 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100220 *
221 * <ul>
222 * <li>{@link Boolean}
223 * <li>{@link Byte}
224 * <li>{@link Short}
225 * <li>{@link Integer}
226 * <li>{@link Long}
227 * <li>{@link String}
228 * <li>{@link Optional} (a GVariant {@code Maybe} type)
229 * <li>{@link List} (a GVariant array)
Matthias Andreas Benkarda66b73d2021-12-18 19:15:52 +0100230 * <li>{@code Object[]} (a GVariant structure)
Matthias Andreas Benkardd6a25d12021-12-28 01:13:58 +0100231 * <li>{@link java.util.Map} (a dictionary)
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100232 * <li>{@link java.util.Map.Entry} (a dictionary entry)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100233 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100234 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100235 *
236 * @return a new {@link Decoder}.
237 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100238 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100239 return new VariantDecoder();
240 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100241
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100242 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100243 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100244 *
245 * @return a new {@link Decoder}.
246 */
247 public static Decoder<Boolean> ofBoolean() {
248 return new BooleanDecoder();
249 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100250
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100251 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100252 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100253 *
254 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
255 * result of this method.
256 *
257 * @return a new {@link Decoder}.
258 */
259 public static Decoder<Byte> ofByte() {
260 return new ByteDecoder();
261 }
262
263 /**
264 * Creates a {@link Decoder} for the 16-bit {@code short} type.
265 *
266 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
267 * result of this method.
268 *
269 * @return a new {@link Decoder}.
270 */
271 public static Decoder<Short> ofShort() {
272 return new ShortDecoder();
273 }
274
275 /**
276 * Creates a {@link Decoder} for the 32-bit {@code int} type.
277 *
278 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
279 * result of this method.
280 *
281 * @return a new {@link Decoder}.
282 */
283 public static Decoder<Integer> ofInt() {
284 return new IntegerDecoder();
285 }
286
287 /**
288 * Creates a {@link Decoder} for the 64-bit {@code long} type.
289 *
290 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
291 * result of this method.
292 *
293 * @return a new {@link Decoder}.
294 */
295 public static Decoder<Long> ofLong() {
296 return new LongDecoder();
297 }
298
299 /**
300 * Creates a {@link Decoder} for the {@code double} type.
301 *
302 * @return a new {@link Decoder}.
303 */
304 public static Decoder<Double> ofDouble() {
305 return new DoubleDecoder();
306 }
307
308 /**
309 * Creates a {@link Decoder} for the {@link String} type.
310 *
311 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
312 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
313 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +0100314 * @param charset the {@link Charset} the string is encoded in.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100315 * @return a new {@link Decoder}.
316 */
317 public static Decoder<String> ofString(Charset charset) {
318 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100319 }
320
321 private static int align(int offset, byte alignment) {
322 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
323 }
324
325 private static int getIntN(ByteBuffer byteSlice) {
326 var intBytes = new byte[4];
327 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
328 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
329 }
330
331 @SuppressWarnings("java:S3358")
332 private static int byteCount(int n) {
333 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
334 }
335
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100336 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100337
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100338 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100339
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100340 ArrayDecoder(Decoder<U> elementDecoder) {
341 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100342 }
343
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100344 @Override
345 public byte alignment() {
346 return elementDecoder.alignment();
347 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100348
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100349 @Override
350 @Nullable
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100351 public Integer fixedSize() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100352 return null;
353 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100354
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100355 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100356 public @NotNull List<U> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100357 List<U> elements;
358
359 var elementSize = elementDecoder.fixedSize();
360 if (elementSize != null) {
361 // A simple C-style array.
362 elements = new ArrayList<>(byteSlice.limit() / elementSize);
363 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100364 var element = elementDecoder.decode(slicePreservingOrder(byteSlice, i, elementSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100365 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100366 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100367 } else if (byteSlice.limit() == 0) {
368 // A degenerate zero-length array of variable width.
369 elements = List.of();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100370 } else {
371 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100372 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100373 int lastFramingOffset =
374 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
375 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100376
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100377 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100378 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100379 for (int i = 0; i < elementCount; i++) {
380 int framingOffset =
381 getIntN(
382 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100383 elements.add(
384 elementDecoder.decode(
385 slicePreservingOrder(byteSlice, position, framingOffset - position)));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100386 position = align(framingOffset, alignment());
387 }
388 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100389
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100390 return elements;
391 }
392 }
393
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100394 private static class DictionaryDecoder<K, V> extends Decoder<Map<K, V>> {
395
396 private final ArrayDecoder<Map.Entry<K, V>> entryArrayDecoder;
397
398 DictionaryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
399 this.entryArrayDecoder =
400 new ArrayDecoder<>(new DictionaryEntryDecoder<>(keyDecoder, valueDecoder));
401 }
402
403 @Override
404 public byte alignment() {
405 return entryArrayDecoder.alignment();
406 }
407
408 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100409 @Nullable
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100410 public Integer fixedSize() {
411 return entryArrayDecoder.fixedSize();
412 }
413
414 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100415 public @NotNull Map<K, V> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard9a6c8ed2021-12-28 01:00:22 +0100416 List<Map.Entry<K, V>> entries = entryArrayDecoder.decode(byteSlice);
417 return entries.stream().collect(toMap(Entry::getKey, Entry::getValue));
418 }
419 }
420
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100421 private static class ByteArrayDecoder extends Decoder<byte[]> {
422
423 private static final int ELEMENT_SIZE = 1;
424
425 @Override
426 public byte alignment() {
427 return ELEMENT_SIZE;
428 }
429
430 @Override
431 @Nullable
432 Integer fixedSize() {
433 return null;
434 }
435
436 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100437 public byte @NotNull [] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100438 // A simple C-style array.
439 byte[] elements = new byte[byteSlice.limit() / ELEMENT_SIZE];
440 byteSlice.get(elements);
441 return elements;
442 }
443 }
444
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100445 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
446
447 private final Decoder<U> elementDecoder;
448
449 MaybeDecoder(Decoder<U> elementDecoder) {
450 this.elementDecoder = elementDecoder;
451 }
452
453 @Override
454 public byte alignment() {
455 return elementDecoder.alignment();
456 }
457
458 @Override
459 @Nullable
460 Integer fixedSize() {
461 return null;
462 }
463
464 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100465 public @NotNull Optional<U> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100466 if (!byteSlice.hasRemaining()) {
467 return Optional.empty();
468 } else {
469 if (!elementDecoder.hasFixedSize()) {
470 // Remove trailing zero byte.
471 byteSlice.limit(byteSlice.limit() - 1);
472 }
473
474 return Optional.of(elementDecoder.decode(byteSlice));
475 }
476 }
477 }
478
479 private static class StructureDecoder<U extends Record> extends Decoder<U> {
480
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100481 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100482 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100483
484 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
485 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100486 if (componentDecoders.length != recordComponents.length) {
487 throw new IllegalArgumentException(
488 "number of decoders (%d) does not match number of structure components (%d)"
489 .formatted(componentDecoders.length, recordComponents.length));
490 }
491
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100492 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100493 this.tupleDecoder = new TupleDecoder(componentDecoders);
494 }
495
496 @Override
497 public byte alignment() {
498 return tupleDecoder.alignment();
499 }
500
501 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100502 public @Nullable Integer fixedSize() {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100503 return tupleDecoder.fixedSize();
504 }
505
506 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100507 public @NotNull U decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100508 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
509
510 try {
511 var recordComponentTypes =
512 Arrays.stream(recordType.getRecordComponents())
513 .map(RecordComponent::getType)
514 .toArray(Class<?>[]::new);
515 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
516 return recordConstructor.newInstance(recordConstructorArguments);
517 } catch (NoSuchMethodException
518 | InstantiationException
519 | IllegalAccessException
520 | InvocationTargetException e) {
521 throw new IllegalStateException(e);
522 }
523 }
524 }
525
526 private static class TupleDecoder extends Decoder<Object[]> {
527
528 private final Decoder<?>[] componentDecoders;
529
530 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100531 this.componentDecoders = componentDecoders;
532 }
533
534 @Override
535 public byte alignment() {
536 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
537 }
538
539 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100540 public @Nullable Integer fixedSize() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100541 int position = 0;
542 for (var componentDecoder : componentDecoders) {
543 var fixedComponentSize = componentDecoder.fixedSize();
544 if (fixedComponentSize == null) {
545 return null;
546 }
547
548 position = align(position, componentDecoder.alignment());
549 position += fixedComponentSize;
550 }
551
552 if (position == 0) {
553 return 1;
554 }
555
556 return align(position, alignment());
557 }
558
559 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100560 public Object @NotNull [] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100561 int framingOffsetSize = byteCount(byteSlice.limit());
562
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100563 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100564
565 int position = 0;
566 int framingOffsetIndex = 0;
567 int componentIndex = 0;
568 for (var componentDecoder : componentDecoders) {
569 position = align(position, componentDecoder.alignment());
570
571 var fixedComponentSize = componentDecoder.fixedSize();
572 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100573 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100574 componentDecoder.decode(
575 slicePreservingOrder(byteSlice, position, fixedComponentSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100576 position += fixedComponentSize;
577 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100578 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100579 // The last component never has a framing offset.
580 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100581 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100582 componentDecoder.decode(
583 slicePreservingOrder(byteSlice, position, endPosition - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100584 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100585 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100586 int framingOffset =
587 getIntN(
588 byteSlice.slice(
589 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
590 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100591 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100592 componentDecoder.decode(
593 slicePreservingOrder(byteSlice, position, framingOffset - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100594 position = framingOffset;
595 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100596 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100597 }
598
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100599 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100600 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100601
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100602 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100603 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100604 }
605
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100606 private static class DictionaryEntryDecoder<K, V> extends Decoder<Map.Entry<K, V>> {
607
608 private final TupleDecoder tupleDecoder;
609
610 DictionaryEntryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
611 this.tupleDecoder = new TupleDecoder(keyDecoder, valueDecoder);
612 }
613
614 @Override
615 public byte alignment() {
616 return tupleDecoder.alignment();
617 }
618
619 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100620 public @Nullable Integer fixedSize() {
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100621 return tupleDecoder.fixedSize();
622 }
623
624 @Override
625 @SuppressWarnings("unchecked")
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100626 public Map.@NotNull Entry<K, V> decode(ByteBuffer byteSlice) {
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100627 Object[] components = tupleDecoder.decode(byteSlice);
628 return new SimpleImmutableEntry<>((K) components[0], (V) components[1]);
629 }
630 }
631
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100632 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100633
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100634 @Override
635 public byte alignment() {
636 return 8;
637 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100638
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100639 @Override
640 @Nullable
641 Integer fixedSize() {
642 return null;
643 }
644
645 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100646 public @NotNull Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100647 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
648 if (byteSlice.get(i) != 0) {
649 continue;
650 }
651
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100652 var dataBytes = slicePreservingOrder(byteSlice, 0, i);
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100653 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100654
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100655 Signature signature;
656 try {
657 signature = Signature.parse(signatureBytes);
658 } catch (ParseException e) {
659 throw new IllegalArgumentException(e);
660 }
661
662 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100663 }
664
665 throw new IllegalArgumentException("variant signature not found");
666 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100667 }
668
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100669 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100670
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100671 @Override
672 public byte alignment() {
673 return 1;
674 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100675
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100676 @Override
677 public Integer fixedSize() {
678 return 1;
679 }
680
681 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100682 public @NotNull Boolean decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100683 return byteSlice.get() != 0;
684 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100685 }
686
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100687 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100688
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100689 @Override
690 public byte alignment() {
691 return 1;
692 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100693
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100694 @Override
695 public Integer fixedSize() {
696 return 1;
697 }
698
699 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100700 public @NotNull Byte decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100701 return byteSlice.get();
702 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100703 }
704
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100705 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100706
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100707 @Override
708 public byte alignment() {
709 return 2;
710 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100711
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100712 @Override
713 public Integer fixedSize() {
714 return 2;
715 }
716
717 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100718 public @NotNull Short decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100719 return byteSlice.getShort();
720 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100721 }
722
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100723 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100724
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100725 @Override
726 public byte alignment() {
727 return 4;
728 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100729
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100730 @Override
731 public Integer fixedSize() {
732 return 4;
733 }
734
735 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100736 public @NotNull Integer decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100737 return byteSlice.getInt();
738 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100739 }
740
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100741 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100742
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100743 @Override
744 public byte alignment() {
745 return 8;
746 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100747
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100748 @Override
749 public Integer fixedSize() {
750 return 8;
751 }
752
753 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100754 public @NotNull Long decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100755 return byteSlice.getLong();
756 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100757 }
758
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100759 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100760
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100761 @Override
762 public byte alignment() {
763 return 8;
764 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100765
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100766 @Override
767 public Integer fixedSize() {
768 return 8;
769 }
770
771 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100772 public @NotNull Double decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100773 return byteSlice.getDouble();
774 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100775 }
776
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100777 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100778
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100779 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100780
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100781 public StringDecoder(Charset charset) {
782 this.charset = charset;
783 }
784
785 @Override
786 public byte alignment() {
787 return 1;
788 }
789
790 @Override
791 @Nullable
792 Integer fixedSize() {
793 return null;
794 }
795
796 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100797 public @NotNull String decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100798 byteSlice.limit(byteSlice.limit() - 1);
799 return charset.decode(byteSlice).toString();
800 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100801 }
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100802
803 private class MappingDecoder<U> extends Decoder<U> {
804
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100805 private final Function<@NotNull T, @NotNull U> function;
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100806
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100807 MappingDecoder(Function<@NotNull T, @NotNull U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100808 this.function = function;
809 }
810
811 @Override
812 public byte alignment() {
813 return Decoder.this.alignment();
814 }
815
816 @Override
817 public @Nullable Integer fixedSize() {
818 return Decoder.this.fixedSize();
819 }
820
821 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100822 public @NotNull U decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100823 return function.apply(Decoder.this.decode(byteSlice));
824 }
825 }
826
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100827 private class ContramappingDecoder extends Decoder<T> {
828
829 private final UnaryOperator<ByteBuffer> function;
830
831 ContramappingDecoder(UnaryOperator<ByteBuffer> function) {
832 this.function = function;
833 }
834
835 @Override
836 public byte alignment() {
837 return Decoder.this.alignment();
838 }
839
840 @Override
841 public @Nullable Integer fixedSize() {
842 return Decoder.this.fixedSize();
843 }
844
845 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100846 public @NotNull T decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100847 var transformedBuffer = function.apply(byteSlice.asReadOnlyBuffer().order(byteSlice.order()));
848 return Decoder.this.decode(transformedBuffer);
849 }
850 }
851
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100852 private class ByteOrderFixingDecoder extends Decoder<T> {
853
854 private final ByteOrder byteOrder;
855
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100856 ByteOrderFixingDecoder(ByteOrder byteOrder) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100857 this.byteOrder = byteOrder;
858 }
859
860 @Override
861 public byte alignment() {
862 return Decoder.this.alignment();
863 }
864
865 @Override
866 public @Nullable Integer fixedSize() {
867 return Decoder.this.fixedSize();
868 }
869
870 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100871 public @NotNull T decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100872 var newByteSlice = byteSlice.duplicate();
873 newByteSlice.order(byteOrder);
874 return Decoder.this.decode(newByteSlice);
875 }
876 }
877
878 private static ByteBuffer slicePreservingOrder(ByteBuffer byteSlice, int index, int length) {
879 return byteSlice.slice(index, length).order(byteSlice.order());
880 }
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100881
882 private static class PredicateDecoder<U> extends Decoder<U> {
883
884 private final Predicate<ByteBuffer> selector;
885 private final Decoder<U> thenDecoder;
886 private final Decoder<U> elseDecoder;
887
888 PredicateDecoder(
889 Predicate<ByteBuffer> selector, Decoder<U> thenDecoder, Decoder<U> elseDecoder) {
890 this.selector = selector;
891 this.thenDecoder = thenDecoder;
892 this.elseDecoder = elseDecoder;
893 if (thenDecoder.alignment() != elseDecoder.alignment()) {
894 throw new IllegalArgumentException(
895 "incompatible alignments in predicate branches: then=%d, else=%d"
896 .formatted(thenDecoder.alignment(), elseDecoder.alignment()));
897 }
898
899 if (!Objects.equals(thenDecoder.fixedSize(), elseDecoder.fixedSize())) {
900 throw new IllegalArgumentException(
901 "incompatible sizes in predicate branches: then=%s, else=%s"
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100902 .formatted(
903 Objects.requireNonNullElse(thenDecoder.fixedSize(), "(null)"),
904 Objects.requireNonNullElse(elseDecoder.fixedSize(), "(null)")));
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100905 }
906 }
907
908 @Override
909 public byte alignment() {
910 return thenDecoder.alignment();
911 }
912
913 @Override
914 public @Nullable Integer fixedSize() {
915 return thenDecoder.fixedSize();
916 }
917
918 @Override
Matthias Andreas Benkard9006e702022-03-01 13:43:50 +0100919 public @NotNull U decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard44df94e2021-12-30 18:43:33 +0100920 var b = selector.test(byteSlice);
921 byteSlice.rewind();
922 return b ? thenDecoder.decode(byteSlice) : elseDecoder.decode(byteSlice);
923 }
924 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100925}