blob: d0c0323a2c7f4b9fe4951d947250af849591a9dd [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 Benkard31c61e72021-12-16 20:06:39 +010010import java.text.ParseException;
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 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010050 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
51 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010052 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
53 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010054 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010055 */
56 public abstract T decode(ByteBuffer byteSlice);
57
58 abstract byte alignment();
59
60 @Nullable
61 abstract Integer fixedSize();
62
63 final boolean hasFixedSize() {
64 return fixedSize() != null;
65 }
66
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010067 /**
68 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
69 *
70 * @param byteOrder the byte order to use.
71 * @return a new, decorated {@link Decoder}.
72 */
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010073 public Decoder<T> withByteOrder(ByteOrder byteOrder) {
74 var delegate = this;
75
76 return new Decoder<>() {
77 @Override
78 public byte alignment() {
79 return delegate.alignment();
80 }
81
82 @Override
83 public @Nullable Integer fixedSize() {
84 return delegate.fixedSize();
85 }
86
87 @Override
88 public T decode(ByteBuffer byteSlice) {
89 byteSlice.order(byteOrder);
90 return delegate.decode(byteSlice);
91 }
92 };
93 }
94
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010095 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010096 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010097 *
98 * @param elementDecoder a {@link Decoder} for the elements of the array.
99 * @param <U> the element type.
100 * @return a new {@link Decoder}.
101 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100102 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100103 return new ArrayDecoder<>(elementDecoder);
104 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100105
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100106 /**
107 * Creates a {@link Decoder} for a {@code Maybe} type.
108 *
109 * @param elementDecoder a {@link Decoder} for the contained element.
110 * @param <U> the element type.
111 * @return a new {@link Decoder}.
112 */
113 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
114 return new MaybeDecoder<>(elementDecoder);
115 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100116
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100117 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100118 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100119 *
120 * @param recordType the {@link Record} type that represents the components of the structure.
121 * @param componentDecoders a {@link Decoder} for each component of the structure.
122 * @param <U> the {@link Record} type that represents the components of the structure.
123 * @return a new {@link Decoder}.
124 */
125 public static <U extends Record> Decoder<U> ofStructure(
126 Class<U> recordType, Decoder<?>... componentDecoders) {
127 return new StructureDecoder<>(recordType, componentDecoders);
128 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100129
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100130 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100131 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
132 *
133 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
134 * more convenient.
135 *
136 * @param componentDecoders a {@link Decoder} for each component of the structure.
137 * @return a new {@link Decoder}.
138 */
139 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
140 return new TupleDecoder(componentDecoders);
141 }
142
143 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100144 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100145 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100146 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100147 *
148 * <ul>
149 * <li>{@link Boolean}
150 * <li>{@link Byte}
151 * <li>{@link Short}
152 * <li>{@link Integer}
153 * <li>{@link Long}
154 * <li>{@link String}
155 * <li>{@link Optional} (a GVariant {@code Maybe} type)
156 * <li>{@link List} (a GVariant array)
157 * <li>{@link Object[]} (a GVariant structure)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100158 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100159 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100160 *
161 * @return a new {@link Decoder}.
162 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100163 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100164 return new VariantDecoder();
165 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100166
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100167 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100168 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100169 *
170 * @return a new {@link Decoder}.
171 */
172 public static Decoder<Boolean> ofBoolean() {
173 return new BooleanDecoder();
174 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100175
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100176 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100177 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100178 *
179 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
180 * result of this method.
181 *
182 * @return a new {@link Decoder}.
183 */
184 public static Decoder<Byte> ofByte() {
185 return new ByteDecoder();
186 }
187
188 /**
189 * Creates a {@link Decoder} for the 16-bit {@code short} type.
190 *
191 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
192 * result of this method.
193 *
194 * @return a new {@link Decoder}.
195 */
196 public static Decoder<Short> ofShort() {
197 return new ShortDecoder();
198 }
199
200 /**
201 * Creates a {@link Decoder} for the 32-bit {@code int} type.
202 *
203 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
204 * result of this method.
205 *
206 * @return a new {@link Decoder}.
207 */
208 public static Decoder<Integer> ofInt() {
209 return new IntegerDecoder();
210 }
211
212 /**
213 * Creates a {@link Decoder} for the 64-bit {@code long} type.
214 *
215 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
216 * result of this method.
217 *
218 * @return a new {@link Decoder}.
219 */
220 public static Decoder<Long> ofLong() {
221 return new LongDecoder();
222 }
223
224 /**
225 * Creates a {@link Decoder} for the {@code double} type.
226 *
227 * @return a new {@link Decoder}.
228 */
229 public static Decoder<Double> ofDouble() {
230 return new DoubleDecoder();
231 }
232
233 /**
234 * Creates a {@link Decoder} for the {@link String} type.
235 *
236 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
237 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
238 *
239 * @return a new {@link Decoder}.
240 */
241 public static Decoder<String> ofString(Charset charset) {
242 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100243 }
244
245 private static int align(int offset, byte alignment) {
246 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
247 }
248
249 private static int getIntN(ByteBuffer byteSlice) {
250 var intBytes = new byte[4];
251 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
252 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
253 }
254
255 @SuppressWarnings("java:S3358")
256 private static int byteCount(int n) {
257 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
258 }
259
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100260 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100261
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100262 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100263
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100264 ArrayDecoder(Decoder<U> elementDecoder) {
265 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100266 }
267
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100268 @Override
269 public byte alignment() {
270 return elementDecoder.alignment();
271 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100272
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100273 @Override
274 @Nullable
275 Integer fixedSize() {
276 return null;
277 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100278
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100279 @Override
280 public List<U> decode(ByteBuffer byteSlice) {
281 List<U> elements;
282
283 var elementSize = elementDecoder.fixedSize();
284 if (elementSize != null) {
285 // A simple C-style array.
286 elements = new ArrayList<>(byteSlice.limit() / elementSize);
287 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
288 var element = elementDecoder.decode(byteSlice.slice(i, elementSize));
289 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100290 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100291 } else {
292 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100293 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100294 int lastFramingOffset =
295 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
296 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100297
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100298 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100299 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100300 for (int i = 0; i < elementCount; i++) {
301 int framingOffset =
302 getIntN(
303 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
304 elements.add(elementDecoder.decode(byteSlice.slice(position, framingOffset - position)));
305 position = align(framingOffset, alignment());
306 }
307 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100308
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100309 return elements;
310 }
311 }
312
313 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
314
315 private final Decoder<U> elementDecoder;
316
317 MaybeDecoder(Decoder<U> elementDecoder) {
318 this.elementDecoder = elementDecoder;
319 }
320
321 @Override
322 public byte alignment() {
323 return elementDecoder.alignment();
324 }
325
326 @Override
327 @Nullable
328 Integer fixedSize() {
329 return null;
330 }
331
332 @Override
333 public Optional<U> decode(ByteBuffer byteSlice) {
334 if (!byteSlice.hasRemaining()) {
335 return Optional.empty();
336 } else {
337 if (!elementDecoder.hasFixedSize()) {
338 // Remove trailing zero byte.
339 byteSlice.limit(byteSlice.limit() - 1);
340 }
341
342 return Optional.of(elementDecoder.decode(byteSlice));
343 }
344 }
345 }
346
347 private static class StructureDecoder<U extends Record> extends Decoder<U> {
348
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100349 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100350 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100351
352 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
353 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100354 if (componentDecoders.length != recordComponents.length) {
355 throw new IllegalArgumentException(
356 "number of decoders (%d) does not match number of structure components (%d)"
357 .formatted(componentDecoders.length, recordComponents.length));
358 }
359
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100360 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100361 this.tupleDecoder = new TupleDecoder(componentDecoders);
362 }
363
364 @Override
365 public byte alignment() {
366 return tupleDecoder.alignment();
367 }
368
369 @Override
370 public Integer fixedSize() {
371 return tupleDecoder.fixedSize();
372 }
373
374 @Override
375 public U decode(ByteBuffer byteSlice) {
376 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
377
378 try {
379 var recordComponentTypes =
380 Arrays.stream(recordType.getRecordComponents())
381 .map(RecordComponent::getType)
382 .toArray(Class<?>[]::new);
383 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
384 return recordConstructor.newInstance(recordConstructorArguments);
385 } catch (NoSuchMethodException
386 | InstantiationException
387 | IllegalAccessException
388 | InvocationTargetException e) {
389 throw new IllegalStateException(e);
390 }
391 }
392 }
393
394 private static class TupleDecoder extends Decoder<Object[]> {
395
396 private final Decoder<?>[] componentDecoders;
397
398 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100399 this.componentDecoders = componentDecoders;
400 }
401
402 @Override
403 public byte alignment() {
404 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
405 }
406
407 @Override
408 public Integer fixedSize() {
409 int position = 0;
410 for (var componentDecoder : componentDecoders) {
411 var fixedComponentSize = componentDecoder.fixedSize();
412 if (fixedComponentSize == null) {
413 return null;
414 }
415
416 position = align(position, componentDecoder.alignment());
417 position += fixedComponentSize;
418 }
419
420 if (position == 0) {
421 return 1;
422 }
423
424 return align(position, alignment());
425 }
426
427 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100428 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100429 int framingOffsetSize = byteCount(byteSlice.limit());
430
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100431 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100432
433 int position = 0;
434 int framingOffsetIndex = 0;
435 int componentIndex = 0;
436 for (var componentDecoder : componentDecoders) {
437 position = align(position, componentDecoder.alignment());
438
439 var fixedComponentSize = componentDecoder.fixedSize();
440 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100441 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100442 componentDecoder.decode(byteSlice.slice(position, fixedComponentSize));
443 position += fixedComponentSize;
444 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100445 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100446 // The last component never has a framing offset.
447 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100448 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100449 componentDecoder.decode(byteSlice.slice(position, endPosition - position));
450 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100451 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100452 int framingOffset =
453 getIntN(
454 byteSlice.slice(
455 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
456 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100457 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100458 componentDecoder.decode(byteSlice.slice(position, framingOffset - position));
459 position = framingOffset;
460 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100461 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100462 }
463
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100464 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100465 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100466
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100467 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100468 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100469 }
470
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100471 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100472
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100473 @Override
474 public byte alignment() {
475 return 8;
476 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100477
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100478 @Override
479 @Nullable
480 Integer fixedSize() {
481 return null;
482 }
483
484 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100485 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100486 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
487 if (byteSlice.get(i) != 0) {
488 continue;
489 }
490
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100491 var dataBytes = byteSlice.slice(0, i);
492 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100493
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100494 Signature signature;
495 try {
496 signature = Signature.parse(signatureBytes);
497 } catch (ParseException e) {
498 throw new IllegalArgumentException(e);
499 }
500
501 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100502 }
503
504 throw new IllegalArgumentException("variant signature not found");
505 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100506 }
507
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100508 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100509
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100510 @Override
511 public byte alignment() {
512 return 1;
513 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100514
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100515 @Override
516 public Integer fixedSize() {
517 return 1;
518 }
519
520 @Override
521 public Boolean decode(ByteBuffer byteSlice) {
522 return byteSlice.get() != 0;
523 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100524 }
525
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100526 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100527
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100528 @Override
529 public byte alignment() {
530 return 1;
531 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100532
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100533 @Override
534 public Integer fixedSize() {
535 return 1;
536 }
537
538 @Override
539 public Byte decode(ByteBuffer byteSlice) {
540 return byteSlice.get();
541 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100542 }
543
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100544 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100545
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100546 @Override
547 public byte alignment() {
548 return 2;
549 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100550
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100551 @Override
552 public Integer fixedSize() {
553 return 2;
554 }
555
556 @Override
557 public Short decode(ByteBuffer byteSlice) {
558 return byteSlice.getShort();
559 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100560 }
561
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100562 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100563
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100564 @Override
565 public byte alignment() {
566 return 4;
567 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100568
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100569 @Override
570 public Integer fixedSize() {
571 return 4;
572 }
573
574 @Override
575 public Integer decode(ByteBuffer byteSlice) {
576 return byteSlice.getInt();
577 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100578 }
579
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100580 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100581
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100582 @Override
583 public byte alignment() {
584 return 8;
585 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100586
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100587 @Override
588 public Integer fixedSize() {
589 return 8;
590 }
591
592 @Override
593 public Long decode(ByteBuffer byteSlice) {
594 return byteSlice.getLong();
595 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100596 }
597
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100598 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100599
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100600 @Override
601 public byte alignment() {
602 return 8;
603 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100604
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100605 @Override
606 public Integer fixedSize() {
607 return 8;
608 }
609
610 @Override
611 public Double decode(ByteBuffer byteSlice) {
612 return byteSlice.getDouble();
613 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100614 }
615
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100616 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100617
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100618 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100619
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100620 public StringDecoder(Charset charset) {
621 this.charset = charset;
622 }
623
624 @Override
625 public byte alignment() {
626 return 1;
627 }
628
629 @Override
630 @Nullable
631 Integer fixedSize() {
632 return null;
633 }
634
635 @Override
636 public String decode(ByteBuffer byteSlice) {
637 byteSlice.limit(byteSlice.limit() - 1);
638 return charset.decode(byteSlice).toString();
639 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100640 }
641}