blob: 9833998a8c83bb455e685fa4c2ca767dcbc6a582 [file] [log] [blame]
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01001package eu.mulk.jgvariant.core;
2
3import static java.nio.ByteOrder.LITTLE_ENDIAN;
4
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01005import java.lang.reflect.InvocationTargetException;
6import java.lang.reflect.RecordComponent;
7import java.nio.ByteBuffer;
8import java.nio.ByteOrder;
9import java.nio.charset.Charset;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010010import java.nio.charset.StandardCharsets;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010011import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.List;
14import java.util.Optional;
15import org.jetbrains.annotations.Nullable;
16
17/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010018 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010019 *
20 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
21 * the type you wish to decode.
22 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010023 * <p><strong>Example</strong>
24 *
25 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
26 * {@code int}, you can use the following code:
27 *
28 * <pre>{@code
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010029 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010030 *
31 * var decoder =
32 * Decoder.ofArray(
33 * Decoder.ofStructure(
34 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010035 * Decoder.ofString(UTF_8),
36 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010037 *
38 * byte[] bytes = ...;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010039 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010040 * }</pre>
41 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010042 * @param <T> the type that the {@link Decoder} can decode.
43 */
44@SuppressWarnings("java:S1610")
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010045public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010046
47 private Decoder() {}
48
49 /**
50 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
51 * data.
52 */
53 public abstract T decode(ByteBuffer byteSlice);
54
55 abstract byte alignment();
56
57 @Nullable
58 abstract Integer fixedSize();
59
60 final boolean hasFixedSize() {
61 return fixedSize() != null;
62 }
63
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010064 /**
65 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
66 *
67 * @param byteOrder the byte order to use.
68 * @return a new, decorated {@link Decoder}.
69 */
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010070 public Decoder<T> withByteOrder(ByteOrder byteOrder) {
71 var delegate = this;
72
73 return new Decoder<>() {
74 @Override
75 public byte alignment() {
76 return delegate.alignment();
77 }
78
79 @Override
80 public @Nullable Integer fixedSize() {
81 return delegate.fixedSize();
82 }
83
84 @Override
85 public T decode(ByteBuffer byteSlice) {
86 byteSlice.order(byteOrder);
87 return delegate.decode(byteSlice);
88 }
89 };
90 }
91
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010092 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010093 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010094 *
95 * @param elementDecoder a {@link Decoder} for the elements of the array.
96 * @param <U> the element type.
97 * @return a new {@link Decoder}.
98 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010099 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100100 return new ArrayDecoder<>(elementDecoder);
101 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100102
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100103 /**
104 * Creates a {@link Decoder} for a {@code Maybe} type.
105 *
106 * @param elementDecoder a {@link Decoder} for the contained element.
107 * @param <U> the element type.
108 * @return a new {@link Decoder}.
109 */
110 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
111 return new MaybeDecoder<>(elementDecoder);
112 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100113
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100114 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100115 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100116 *
117 * @param recordType the {@link Record} type that represents the components of the structure.
118 * @param componentDecoders a {@link Decoder} for each component of the structure.
119 * @param <U> the {@link Record} type that represents the components of the structure.
120 * @return a new {@link Decoder}.
121 */
122 public static <U extends Record> Decoder<U> ofStructure(
123 Class<U> recordType, Decoder<?>... componentDecoders) {
124 return new StructureDecoder<>(recordType, componentDecoders);
125 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100126
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100127 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100128 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
129 *
130 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
131 * more convenient.
132 *
133 * @param componentDecoders a {@link Decoder} for each component of the structure.
134 * @return a new {@link Decoder}.
135 */
136 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
137 return new TupleDecoder(componentDecoders);
138 }
139
140 /**
141 * Creates a {@link Decoder} for the {@code Variant} type.
142 *
143 * <p>The returned {@link Object} can be of one of the following types:
144 *
145 * <ul>
146 * <li>{@link Boolean}
147 * <li>{@link Byte}
148 * <li>{@link Short}
149 * <li>{@link Integer}
150 * <li>{@link Long}
151 * <li>{@link String}
152 * <li>{@link Optional} (a GVariant {@code Maybe} type)
153 * <li>{@link List} (a GVariant array)
154 * <li>{@link Object[]} (a GVariant structure)
155 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100156 *
157 * @return a new {@link Decoder}.
158 */
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100159 public static Decoder<Object> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100160 return new VariantDecoder();
161 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100162
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100163 /**
164 * Creates a {@link Decoder} for the {@code Boolean} type.
165 *
166 * @return a new {@link Decoder}.
167 */
168 public static Decoder<Boolean> ofBoolean() {
169 return new BooleanDecoder();
170 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100171
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100172 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100173 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100174 *
175 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
176 * result of this method.
177 *
178 * @return a new {@link Decoder}.
179 */
180 public static Decoder<Byte> ofByte() {
181 return new ByteDecoder();
182 }
183
184 /**
185 * Creates a {@link Decoder} for the 16-bit {@code short} type.
186 *
187 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
188 * result of this method.
189 *
190 * @return a new {@link Decoder}.
191 */
192 public static Decoder<Short> ofShort() {
193 return new ShortDecoder();
194 }
195
196 /**
197 * Creates a {@link Decoder} for the 32-bit {@code int} type.
198 *
199 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
200 * result of this method.
201 *
202 * @return a new {@link Decoder}.
203 */
204 public static Decoder<Integer> ofInt() {
205 return new IntegerDecoder();
206 }
207
208 /**
209 * Creates a {@link Decoder} for the 64-bit {@code long} type.
210 *
211 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
212 * result of this method.
213 *
214 * @return a new {@link Decoder}.
215 */
216 public static Decoder<Long> ofLong() {
217 return new LongDecoder();
218 }
219
220 /**
221 * Creates a {@link Decoder} for the {@code double} type.
222 *
223 * @return a new {@link Decoder}.
224 */
225 public static Decoder<Double> ofDouble() {
226 return new DoubleDecoder();
227 }
228
229 /**
230 * Creates a {@link Decoder} for the {@link String} type.
231 *
232 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
233 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
234 *
235 * @return a new {@link Decoder}.
236 */
237 public static Decoder<String> ofString(Charset charset) {
238 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100239 }
240
241 private static int align(int offset, byte alignment) {
242 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
243 }
244
245 private static int getIntN(ByteBuffer byteSlice) {
246 var intBytes = new byte[4];
247 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
248 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
249 }
250
251 @SuppressWarnings("java:S3358")
252 private static int byteCount(int n) {
253 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
254 }
255
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100256 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100257
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100258 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100259
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100260 ArrayDecoder(Decoder<U> elementDecoder) {
261 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100262 }
263
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100264 @Override
265 public byte alignment() {
266 return elementDecoder.alignment();
267 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100268
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100269 @Override
270 @Nullable
271 Integer fixedSize() {
272 return null;
273 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100274
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100275 @Override
276 public List<U> decode(ByteBuffer byteSlice) {
277 List<U> elements;
278
279 var elementSize = elementDecoder.fixedSize();
280 if (elementSize != null) {
281 // A simple C-style array.
282 elements = new ArrayList<>(byteSlice.limit() / elementSize);
283 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
284 var element = elementDecoder.decode(byteSlice.slice(i, elementSize));
285 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100286 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100287 } else {
288 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100289 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100290 int lastFramingOffset =
291 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
292 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100293
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100294 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100295 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100296 for (int i = 0; i < elementCount; i++) {
297 int framingOffset =
298 getIntN(
299 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
300 elements.add(elementDecoder.decode(byteSlice.slice(position, framingOffset - position)));
301 position = align(framingOffset, alignment());
302 }
303 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100304
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100305 return elements;
306 }
307 }
308
309 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
310
311 private final Decoder<U> elementDecoder;
312
313 MaybeDecoder(Decoder<U> elementDecoder) {
314 this.elementDecoder = elementDecoder;
315 }
316
317 @Override
318 public byte alignment() {
319 return elementDecoder.alignment();
320 }
321
322 @Override
323 @Nullable
324 Integer fixedSize() {
325 return null;
326 }
327
328 @Override
329 public Optional<U> decode(ByteBuffer byteSlice) {
330 if (!byteSlice.hasRemaining()) {
331 return Optional.empty();
332 } else {
333 if (!elementDecoder.hasFixedSize()) {
334 // Remove trailing zero byte.
335 byteSlice.limit(byteSlice.limit() - 1);
336 }
337
338 return Optional.of(elementDecoder.decode(byteSlice));
339 }
340 }
341 }
342
343 private static class StructureDecoder<U extends Record> extends Decoder<U> {
344
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100345 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100346 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100347
348 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
349 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100350 if (componentDecoders.length != recordComponents.length) {
351 throw new IllegalArgumentException(
352 "number of decoders (%d) does not match number of structure components (%d)"
353 .formatted(componentDecoders.length, recordComponents.length));
354 }
355
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100356 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100357 this.tupleDecoder = new TupleDecoder(componentDecoders);
358 }
359
360 @Override
361 public byte alignment() {
362 return tupleDecoder.alignment();
363 }
364
365 @Override
366 public Integer fixedSize() {
367 return tupleDecoder.fixedSize();
368 }
369
370 @Override
371 public U decode(ByteBuffer byteSlice) {
372 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
373
374 try {
375 var recordComponentTypes =
376 Arrays.stream(recordType.getRecordComponents())
377 .map(RecordComponent::getType)
378 .toArray(Class<?>[]::new);
379 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
380 return recordConstructor.newInstance(recordConstructorArguments);
381 } catch (NoSuchMethodException
382 | InstantiationException
383 | IllegalAccessException
384 | InvocationTargetException e) {
385 throw new IllegalStateException(e);
386 }
387 }
388 }
389
390 private static class TupleDecoder extends Decoder<Object[]> {
391
392 private final Decoder<?>[] componentDecoders;
393
394 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100395 this.componentDecoders = componentDecoders;
396 }
397
398 @Override
399 public byte alignment() {
400 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
401 }
402
403 @Override
404 public Integer fixedSize() {
405 int position = 0;
406 for (var componentDecoder : componentDecoders) {
407 var fixedComponentSize = componentDecoder.fixedSize();
408 if (fixedComponentSize == null) {
409 return null;
410 }
411
412 position = align(position, componentDecoder.alignment());
413 position += fixedComponentSize;
414 }
415
416 if (position == 0) {
417 return 1;
418 }
419
420 return align(position, alignment());
421 }
422
423 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100424 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100425 int framingOffsetSize = byteCount(byteSlice.limit());
426
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100427 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100428
429 int position = 0;
430 int framingOffsetIndex = 0;
431 int componentIndex = 0;
432 for (var componentDecoder : componentDecoders) {
433 position = align(position, componentDecoder.alignment());
434
435 var fixedComponentSize = componentDecoder.fixedSize();
436 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100437 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100438 componentDecoder.decode(byteSlice.slice(position, fixedComponentSize));
439 position += fixedComponentSize;
440 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100441 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100442 // The last component never has a framing offset.
443 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100444 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100445 componentDecoder.decode(byteSlice.slice(position, endPosition - position));
446 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100447 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100448 int framingOffset =
449 getIntN(
450 byteSlice.slice(
451 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
452 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100453 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100454 componentDecoder.decode(byteSlice.slice(position, framingOffset - position));
455 position = framingOffset;
456 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100457 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100458 }
459
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100460 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100461 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100462
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100463 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100464 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100465 }
466
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100467 private static class VariantDecoder extends Decoder<Object> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100468
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100469 @Override
470 public byte alignment() {
471 return 8;
472 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100473
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100474 @Override
475 @Nullable
476 Integer fixedSize() {
477 return null;
478 }
479
480 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100481 public Object decode(ByteBuffer byteSlice) {
482 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
483 if (byteSlice.get(i) != 0) {
484 continue;
485 }
486
487 var data = byteSlice.slice(0, i);
488 var signature = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
489
490 Decoder<?> decoder = parseSignature(signature);
491 return decoder.decode(data);
492 }
493
494 throw new IllegalArgumentException("variant signature not found");
495 }
496
497 private static Decoder<?> parseSignature(ByteBuffer signature) {
498 char c = (char) signature.get();
499 return switch (c) {
500 case 'b' -> Decoder.ofBoolean();
501 case 'y' -> Decoder.ofByte();
502 case 'n', 'q' -> Decoder.ofShort();
503 case 'i', 'u' -> Decoder.ofInt();
504 case 'x', 't' -> Decoder.ofLong();
505 case 'd' -> Decoder.ofDouble();
506 case 's', 'o', 'g' -> Decoder.ofString(StandardCharsets.UTF_8);
507 case 'v' -> Decoder.ofVariant();
508 case 'm' -> Decoder.ofMaybe(parseSignature(signature));
509 case 'a' -> Decoder.ofArray(parseSignature(signature));
510 case '(', '{' -> Decoder.ofStructure(parseTupleTypes(signature).toArray(new Decoder<?>[0]));
511 default -> throw new IllegalArgumentException(
512 String.format("encountered unknown signature byte '%c'", c));
513 };
514 }
515
516 private static List<Decoder<?>> parseTupleTypes(ByteBuffer signature) {
517 List<Decoder<?>> decoders = new ArrayList<>();
518
519 while (true) {
520 char c = (char) signature.get(signature.position());
521 if (c == ')' || c == '}') {
522 signature.get();
523 break;
524 }
525
526 decoders.add(parseSignature(signature));
527 }
528
529 return decoders;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100530 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100531 }
532
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100533 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100534
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100535 @Override
536 public byte alignment() {
537 return 1;
538 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100539
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100540 @Override
541 public Integer fixedSize() {
542 return 1;
543 }
544
545 @Override
546 public Boolean decode(ByteBuffer byteSlice) {
547 return byteSlice.get() != 0;
548 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100549 }
550
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100551 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100552
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100553 @Override
554 public byte alignment() {
555 return 1;
556 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100557
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100558 @Override
559 public Integer fixedSize() {
560 return 1;
561 }
562
563 @Override
564 public Byte decode(ByteBuffer byteSlice) {
565 return byteSlice.get();
566 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100567 }
568
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100569 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100570
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100571 @Override
572 public byte alignment() {
573 return 2;
574 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100575
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100576 @Override
577 public Integer fixedSize() {
578 return 2;
579 }
580
581 @Override
582 public Short decode(ByteBuffer byteSlice) {
583 return byteSlice.getShort();
584 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100585 }
586
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100587 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100588
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100589 @Override
590 public byte alignment() {
591 return 4;
592 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100593
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100594 @Override
595 public Integer fixedSize() {
596 return 4;
597 }
598
599 @Override
600 public Integer decode(ByteBuffer byteSlice) {
601 return byteSlice.getInt();
602 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100603 }
604
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100605 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100606
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100607 @Override
608 public byte alignment() {
609 return 8;
610 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100611
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100612 @Override
613 public Integer fixedSize() {
614 return 8;
615 }
616
617 @Override
618 public Long decode(ByteBuffer byteSlice) {
619 return byteSlice.getLong();
620 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100621 }
622
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100623 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100624
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100625 @Override
626 public byte alignment() {
627 return 8;
628 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100629
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100630 @Override
631 public Integer fixedSize() {
632 return 8;
633 }
634
635 @Override
636 public Double decode(ByteBuffer byteSlice) {
637 return byteSlice.getDouble();
638 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100639 }
640
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100641 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100642
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100643 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100644
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100645 public StringDecoder(Charset charset) {
646 this.charset = charset;
647 }
648
649 @Override
650 public byte alignment() {
651 return 1;
652 }
653
654 @Override
655 @Nullable
656 Integer fixedSize() {
657 return null;
658 }
659
660 @Override
661 public String decode(ByteBuffer byteSlice) {
662 byteSlice.limit(byteSlice.limit() - 1);
663 return charset.decode(byteSlice).toString();
664 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100665 }
666}