From cd924f6efbb40993eb12ed2c6e6547d8b505d439 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Tue, 28 Dec 2021 00:46:06 +0100 Subject: Add Decoder#ofDictionaryEntry. Change-Id: Ie78096e1a7cfd3bcfa446e3ababe15b910d0c23c --- .../main/java/eu/mulk/jgvariant/core/Decoder.java | 42 ++++++++++++++++++++++ .../java/eu/mulk/jgvariant/core/Signature.java | 12 ++++++- .../main/java/eu/mulk/jgvariant/core/Variant.java | 1 + .../java/eu/mulk/jgvariant/core/DecoderTest.java | 14 +++++++- 4 files changed, 67 insertions(+), 2 deletions(-) (limited to 'jgvariant-core/src') diff --git a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java index fee0407..96e1332 100644 --- a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java +++ b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java @@ -8,9 +8,11 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; import java.text.ParseException; +import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.function.Function; import org.apiguardian.api.API; @@ -154,6 +156,19 @@ public abstract class Decoder { return new TupleDecoder(componentDecoders); } + /** + * Creates a {@link Decoder} for a {@code Dictionary Entry} type, decoding into a {@link + * Map.Entry}. + * + * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry. + * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry. + * @return a new {@link Decoder}. + */ + public static Decoder> ofDictionaryEntry( + Decoder keyDecoder, Decoder valueDecoder) { + return new DictionaryEntryDecoder<>(keyDecoder, valueDecoder); + } + /** * Creates a {@link Decoder} for the {@link Variant} type. * @@ -169,6 +184,7 @@ public abstract class Decoder { *
  • {@link Optional} (a GVariant {@code Maybe} type) *
  • {@link List} (a GVariant array) *
  • {@code Object[]} (a GVariant structure) + *
  • {@link java.util.Map.Entry} (a dictionary entry) *
  • {@link Variant} (a nested variant) * * @@ -515,6 +531,32 @@ public abstract class Decoder { } } + private static class DictionaryEntryDecoder extends Decoder> { + + private final TupleDecoder tupleDecoder; + + DictionaryEntryDecoder(Decoder keyDecoder, Decoder valueDecoder) { + this.tupleDecoder = new TupleDecoder(keyDecoder, valueDecoder); + } + + @Override + public byte alignment() { + return tupleDecoder.alignment(); + } + + @Override + public Integer fixedSize() { + return tupleDecoder.fixedSize(); + } + + @Override + @SuppressWarnings("unchecked") + public Map.Entry decode(ByteBuffer byteSlice) { + Object[] components = tupleDecoder.decode(byteSlice); + return new SimpleImmutableEntry<>((K) components[0], (V) components[1]); + } + } + private static class VariantDecoder extends Decoder { @Override diff --git a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Signature.java b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Signature.java index 78e4bdd..6a4d01d 100644 --- a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Signature.java +++ b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Signature.java @@ -92,7 +92,17 @@ public final class Signature { case 'v' -> Decoder.ofVariant(); case 'm' -> Decoder.ofMaybe(parseSignature(signature)); case 'a' -> Decoder.ofArray(parseSignature(signature)); - case '(', '{' -> Decoder.ofStructure(parseTupleTypes(signature).toArray(new Decoder[0])); + case '(' -> Decoder.ofStructure(parseTupleTypes(signature).toArray(new Decoder[0])); + case '{' -> { + var tupleTypes = parseTupleTypes(signature); + if (tupleTypes.size() != 2) { + throw new ParseException( + String.format( + "dictionary entry type with %d components, expected 2", tupleTypes.size()), + signature.position()); + } + yield Decoder.ofDictionaryEntry(tupleTypes.get(0), tupleTypes.get(1)); + } default -> throw new ParseException( String.format("encountered unknown signature byte '%c'", c), signature.position()); }; diff --git a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Variant.java b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Variant.java index d1c1049..34d3945 100644 --- a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Variant.java +++ b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Variant.java @@ -18,6 +18,7 @@ import org.apiguardian.api.API.Status; *
  • {@link java.util.Optional} (a GVariant {@code Maybe} type) *
  • {@link java.util.List} (a GVariant array) *
  • {@code Object[]} (a GVariant structure) + *
  • {@link java.util.Map.Entry} (a dictionary entry) *
  • {@link Variant} (a nested variant) * * diff --git a/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java b/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java index d72a1b6..ab7de44 100644 --- a/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java +++ b/jgvariant-core/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java @@ -11,6 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.nio.ByteBuffer; import java.text.ParseException; import java.util.List; +import java.util.Map; import java.util.Optional; import org.junit.jupiter.api.Test; @@ -271,7 +272,18 @@ class DecoderTest { } @Test - void testDictionaryEntry() { + void testDictionaryEntryAsMapEntry() { + var data = + new byte[] {0x61, 0x20, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06}; + + var decoder = + Decoder.ofDictionaryEntry( + Decoder.ofString(UTF_8), Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)); + assertEquals(Map.entry("a key", 514), decoder.decode(ByteBuffer.wrap(data))); + } + + @Test + void testDictionaryEntryAsRecord() { var data = new byte[] {0x61, 0x20, 0x6B, 0x65, 0x79, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06}; -- cgit v1.2.3