blob: 389ae85b4ce7c1a89436e8c186dd4e92e72c6e6a [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 /**
144 * Creates a {@link Decoder} for the {@code Variant} type.
145 *
146 * <p>The returned {@link Object} can be of one of the following types:
147 *
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)
158 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100159 *
160 * @return a new {@link Decoder}.
161 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100162 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100163 return new VariantDecoder();
164 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100165
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100166 /**
167 * Creates a {@link Decoder} for the {@code Boolean} type.
168 *
169 * @return a new {@link Decoder}.
170 */
171 public static Decoder<Boolean> ofBoolean() {
172 return new BooleanDecoder();
173 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100174
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100175 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100176 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100177 *
178 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
179 * result of this method.
180 *
181 * @return a new {@link Decoder}.
182 */
183 public static Decoder<Byte> ofByte() {
184 return new ByteDecoder();
185 }
186
187 /**
188 * Creates a {@link Decoder} for the 16-bit {@code short} type.
189 *
190 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
191 * result of this method.
192 *
193 * @return a new {@link Decoder}.
194 */
195 public static Decoder<Short> ofShort() {
196 return new ShortDecoder();
197 }
198
199 /**
200 * Creates a {@link Decoder} for the 32-bit {@code int} type.
201 *
202 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
203 * result of this method.
204 *
205 * @return a new {@link Decoder}.
206 */
207 public static Decoder<Integer> ofInt() {
208 return new IntegerDecoder();
209 }
210
211 /**
212 * Creates a {@link Decoder} for the 64-bit {@code long} type.
213 *
214 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
215 * result of this method.
216 *
217 * @return a new {@link Decoder}.
218 */
219 public static Decoder<Long> ofLong() {
220 return new LongDecoder();
221 }
222
223 /**
224 * Creates a {@link Decoder} for the {@code double} type.
225 *
226 * @return a new {@link Decoder}.
227 */
228 public static Decoder<Double> ofDouble() {
229 return new DoubleDecoder();
230 }
231
232 /**
233 * Creates a {@link Decoder} for the {@link String} type.
234 *
235 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
236 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
237 *
238 * @return a new {@link Decoder}.
239 */
240 public static Decoder<String> ofString(Charset charset) {
241 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100242 }
243
244 private static int align(int offset, byte alignment) {
245 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
246 }
247
248 private static int getIntN(ByteBuffer byteSlice) {
249 var intBytes = new byte[4];
250 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
251 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
252 }
253
254 @SuppressWarnings("java:S3358")
255 private static int byteCount(int n) {
256 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
257 }
258
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100259 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100260
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100261 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100262
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100263 ArrayDecoder(Decoder<U> elementDecoder) {
264 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100265 }
266
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100267 @Override
268 public byte alignment() {
269 return elementDecoder.alignment();
270 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100271
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100272 @Override
273 @Nullable
274 Integer fixedSize() {
275 return null;
276 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100277
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100278 @Override
279 public List<U> decode(ByteBuffer byteSlice) {
280 List<U> elements;
281
282 var elementSize = elementDecoder.fixedSize();
283 if (elementSize != null) {
284 // A simple C-style array.
285 elements = new ArrayList<>(byteSlice.limit() / elementSize);
286 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
287 var element = elementDecoder.decode(byteSlice.slice(i, elementSize));
288 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100289 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100290 } else {
291 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100292 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100293 int lastFramingOffset =
294 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
295 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100296
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100297 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100298 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100299 for (int i = 0; i < elementCount; i++) {
300 int framingOffset =
301 getIntN(
302 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
303 elements.add(elementDecoder.decode(byteSlice.slice(position, framingOffset - position)));
304 position = align(framingOffset, alignment());
305 }
306 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100307
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100308 return elements;
309 }
310 }
311
312 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
313
314 private final Decoder<U> elementDecoder;
315
316 MaybeDecoder(Decoder<U> elementDecoder) {
317 this.elementDecoder = elementDecoder;
318 }
319
320 @Override
321 public byte alignment() {
322 return elementDecoder.alignment();
323 }
324
325 @Override
326 @Nullable
327 Integer fixedSize() {
328 return null;
329 }
330
331 @Override
332 public Optional<U> decode(ByteBuffer byteSlice) {
333 if (!byteSlice.hasRemaining()) {
334 return Optional.empty();
335 } else {
336 if (!elementDecoder.hasFixedSize()) {
337 // Remove trailing zero byte.
338 byteSlice.limit(byteSlice.limit() - 1);
339 }
340
341 return Optional.of(elementDecoder.decode(byteSlice));
342 }
343 }
344 }
345
346 private static class StructureDecoder<U extends Record> extends Decoder<U> {
347
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100348 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100349 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100350
351 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
352 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100353 if (componentDecoders.length != recordComponents.length) {
354 throw new IllegalArgumentException(
355 "number of decoders (%d) does not match number of structure components (%d)"
356 .formatted(componentDecoders.length, recordComponents.length));
357 }
358
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100359 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100360 this.tupleDecoder = new TupleDecoder(componentDecoders);
361 }
362
363 @Override
364 public byte alignment() {
365 return tupleDecoder.alignment();
366 }
367
368 @Override
369 public Integer fixedSize() {
370 return tupleDecoder.fixedSize();
371 }
372
373 @Override
374 public U decode(ByteBuffer byteSlice) {
375 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
376
377 try {
378 var recordComponentTypes =
379 Arrays.stream(recordType.getRecordComponents())
380 .map(RecordComponent::getType)
381 .toArray(Class<?>[]::new);
382 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
383 return recordConstructor.newInstance(recordConstructorArguments);
384 } catch (NoSuchMethodException
385 | InstantiationException
386 | IllegalAccessException
387 | InvocationTargetException e) {
388 throw new IllegalStateException(e);
389 }
390 }
391 }
392
393 private static class TupleDecoder extends Decoder<Object[]> {
394
395 private final Decoder<?>[] componentDecoders;
396
397 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100398 this.componentDecoders = componentDecoders;
399 }
400
401 @Override
402 public byte alignment() {
403 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
404 }
405
406 @Override
407 public Integer fixedSize() {
408 int position = 0;
409 for (var componentDecoder : componentDecoders) {
410 var fixedComponentSize = componentDecoder.fixedSize();
411 if (fixedComponentSize == null) {
412 return null;
413 }
414
415 position = align(position, componentDecoder.alignment());
416 position += fixedComponentSize;
417 }
418
419 if (position == 0) {
420 return 1;
421 }
422
423 return align(position, alignment());
424 }
425
426 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100427 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100428 int framingOffsetSize = byteCount(byteSlice.limit());
429
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100430 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100431
432 int position = 0;
433 int framingOffsetIndex = 0;
434 int componentIndex = 0;
435 for (var componentDecoder : componentDecoders) {
436 position = align(position, componentDecoder.alignment());
437
438 var fixedComponentSize = componentDecoder.fixedSize();
439 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100440 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100441 componentDecoder.decode(byteSlice.slice(position, fixedComponentSize));
442 position += fixedComponentSize;
443 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100444 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100445 // The last component never has a framing offset.
446 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100447 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100448 componentDecoder.decode(byteSlice.slice(position, endPosition - position));
449 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100450 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100451 int framingOffset =
452 getIntN(
453 byteSlice.slice(
454 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
455 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100456 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100457 componentDecoder.decode(byteSlice.slice(position, framingOffset - position));
458 position = framingOffset;
459 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100460 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100461 }
462
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100463 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100464 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100465
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100466 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100467 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100468 }
469
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100470 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100471
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100472 @Override
473 public byte alignment() {
474 return 8;
475 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100476
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100477 @Override
478 @Nullable
479 Integer fixedSize() {
480 return null;
481 }
482
483 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100484 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100485 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
486 if (byteSlice.get(i) != 0) {
487 continue;
488 }
489
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100490 var dataBytes = byteSlice.slice(0, i);
491 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100492
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100493 Signature signature;
494 try {
495 signature = Signature.parse(signatureBytes);
496 } catch (ParseException e) {
497 throw new IllegalArgumentException(e);
498 }
499
500 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100501 }
502
503 throw new IllegalArgumentException("variant signature not found");
504 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100505 }
506
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100507 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100508
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100509 @Override
510 public byte alignment() {
511 return 1;
512 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100513
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100514 @Override
515 public Integer fixedSize() {
516 return 1;
517 }
518
519 @Override
520 public Boolean decode(ByteBuffer byteSlice) {
521 return byteSlice.get() != 0;
522 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100523 }
524
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100525 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100526
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100527 @Override
528 public byte alignment() {
529 return 1;
530 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100531
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100532 @Override
533 public Integer fixedSize() {
534 return 1;
535 }
536
537 @Override
538 public Byte decode(ByteBuffer byteSlice) {
539 return byteSlice.get();
540 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100541 }
542
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100543 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100544
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100545 @Override
546 public byte alignment() {
547 return 2;
548 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100549
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100550 @Override
551 public Integer fixedSize() {
552 return 2;
553 }
554
555 @Override
556 public Short decode(ByteBuffer byteSlice) {
557 return byteSlice.getShort();
558 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100559 }
560
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100561 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100562
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100563 @Override
564 public byte alignment() {
565 return 4;
566 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100567
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100568 @Override
569 public Integer fixedSize() {
570 return 4;
571 }
572
573 @Override
574 public Integer decode(ByteBuffer byteSlice) {
575 return byteSlice.getInt();
576 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100577 }
578
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100579 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100580
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100581 @Override
582 public byte alignment() {
583 return 8;
584 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100585
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100586 @Override
587 public Integer fixedSize() {
588 return 8;
589 }
590
591 @Override
592 public Long decode(ByteBuffer byteSlice) {
593 return byteSlice.getLong();
594 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100595 }
596
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100597 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100598
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100599 @Override
600 public byte alignment() {
601 return 8;
602 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100603
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100604 @Override
605 public Integer fixedSize() {
606 return 8;
607 }
608
609 @Override
610 public Double decode(ByteBuffer byteSlice) {
611 return byteSlice.getDouble();
612 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100613 }
614
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100615 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100616
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100617 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100618
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100619 public StringDecoder(Charset charset) {
620 this.charset = charset;
621 }
622
623 @Override
624 public byte alignment() {
625 return 1;
626 }
627
628 @Override
629 @Nullable
630 Integer fixedSize() {
631 return null;
632 }
633
634 @Override
635 public String decode(ByteBuffer byteSlice) {
636 byteSlice.limit(byteSlice.limit() - 1);
637 return charset.decode(byteSlice).toString();
638 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100639 }
640}