Javadocs and README.

Change-Id: I10d7cb87ca22475f3f73fb25acd813aa1f8d2bb8
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e482857
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# GVariant for Java
+
+This library provides a [GVariant][] parser in pure Java.
+
+
+## Overview
+
+The two foundational classes are `Value` and `Decoder`.
+
+`Value` is a sum type (sealed interface) that represents a
+[GVariant][] value.  Its subtypes represent the different types of
+values that [GVariant][] supports.
+
+Instances of `Decoder` read a given concrete subtype of `Value` from a
+[ByteBuffer][].  The class also contains factory methods to create
+those instances.
+
+The various subclasses of `Decoder` together implement the [GVariant
+serialization][] specification.
+
+
+## Example
+
+To parse a [GVariant][] value of type `"a(si)"`, which is an array of
+pairs of [String][] and `int`, you can use the following code:
+
+    record ExampleRecord(Value.Str s, Value.Int32 i) {}
+    
+    var decoder =
+      Decoder.ofArray(
+        Decoder.ofStructure(
+          ExampleRecord.class,
+          Decoder.ofStr(StandardCharsets.UTF_8),
+          Decoder.ofInt32().withByteOrder(ByteOrder.LITTLE_ENDIAN)));
+    
+    byte[] bytes = ...;
+    Value.Array<Value.Structure<ExampleRecord>> example = decoder.decode(bytes);
+
+
+[ByteBuffer]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/nio/ByteBuffer.html
+[GVariant]: https://docs.gtk.org/glib/struct.Variant.html
+[GVariant serialization]: https://people.gnome.org/~desrt/gvariant-serialisation.pdf
+[String]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html
diff --git a/src/main/java/eu/mulk/jgvariant/core/Decoder.java b/src/main/java/eu/mulk/jgvariant/core/Decoder.java
index 2ebd0af..c51a723 100644
--- a/src/main/java/eu/mulk/jgvariant/core/Decoder.java
+++ b/src/main/java/eu/mulk/jgvariant/core/Decoder.java
@@ -30,6 +30,25 @@
  * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
  * the type you wish to decode.
  *
+ * <p><strong>Example</strong>
+ *
+ * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
+ * {@code int}, you can use the following code:
+ *
+ * <pre>{@code
+ * record ExampleRecord(Value.Str s, Value.Int32 i) {}
+ *
+ * var decoder =
+ *   Decoder.ofArray(
+ *     Decoder.ofStructure(
+ *       ExampleRecord.class,
+ *       Decoder.ofStr(UTF_8),
+ *       Decoder.ofInt32().withByteOrder(LITTLE_ENDIAN)));
+ *
+ * byte[] bytes = ...;
+ * Value.Array<Value.Structure<ExampleRecord>> example = decoder.decode(ByteBuffer.wrap(bytes));
+ * }</pre>
+ *
  * @param <T> the type that the {@link Decoder} can decode.
  */
 @SuppressWarnings("java:S1610")
@@ -52,6 +71,12 @@
     return fixedSize() != null;
   }
 
+  /**
+   * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
+   *
+   * @param byteOrder the byte order to use.
+   * @return a new, decorated {@link Decoder}.
+   */
   public Decoder<T> withByteOrder(ByteOrder byteOrder) {
     var delegate = this;
 
@@ -74,6 +99,13 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for an {@link Array} type.
+   *
+   * @param elementDecoder a {@link Decoder} for the elements of the array.
+   * @param <U> the element type.
+   * @return a new {@link Decoder}.
+   */
   public static <U extends Value> Decoder<Array<U>> ofArray(Decoder<U> elementDecoder) {
     return new Decoder<>() {
       @Override
@@ -138,6 +170,13 @@
     return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
   }
 
+  /**
+   * Creates a {@link Decoder} for a {@link Maybe} type.
+   *
+   * @param elementDecoder a {@link Decoder} for the contained element.
+   * @param <U> the element type.
+   * @return a new {@link Decoder}.
+   */
   public static <U extends Value> Decoder<Maybe<U>> ofMaybe(Decoder<U> elementDecoder) {
     return new Decoder<>() {
       @Override
@@ -167,6 +206,14 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for a {@link Structure} type.
+   *
+   * @param recordType the {@link Record} type that represents the components of the structure.
+   * @param componentDecoders a {@link Decoder} for each component of the structure.
+   * @param <U> the {@link Record} type that represents the components of the structure.
+   * @return a new {@link Decoder}.
+   */
   @SafeVarargs
   public static <U extends Record> Decoder<Structure<U>> ofStructure(
       Class<U> recordType, Decoder<? extends Value>... componentDecoders) {
@@ -260,6 +307,11 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Variant} type.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Variant> ofVariant() {
     return new Decoder<>() {
       @Override
@@ -281,7 +333,12 @@
     };
   }
 
-  public static Decoder<Bool> ofBoolean() {
+  /**
+   * Creates a {@link Decoder} for the {@link Bool} type.
+   *
+   * @return a new {@link Decoder}.
+   */
+  public static Decoder<Bool> ofBool() {
     return new Decoder<>() {
       @Override
       public byte alignment() {
@@ -300,6 +357,14 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Int8} type.
+   *
+   * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
+   * result of this method.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Int8> ofInt8() {
     return new Decoder<>() {
       @Override
@@ -319,6 +384,14 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Int16} type.
+   *
+   * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
+   * result of this method.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Int16> ofInt16() {
     return new Decoder<>() {
       @Override
@@ -338,6 +411,14 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Int32} type.
+   *
+   * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
+   * result of this method.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Int32> ofInt32() {
     return new Decoder<>() {
       @Override
@@ -357,6 +438,14 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Int64} type.
+   *
+   * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
+   * result of this method.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Int64> ofInt64() {
     return new Decoder<>() {
       @Override
@@ -376,6 +465,11 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Float64} type.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Float64> ofFloat64() {
     return new Decoder<>() {
       @Override
@@ -395,6 +489,14 @@
     };
   }
 
+  /**
+   * Creates a {@link Decoder} for the {@link Str} type.
+   *
+   * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
+   * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
+   *
+   * @return a new {@link Decoder}.
+   */
   public static Decoder<Str> ofStr(Charset charset) {
     return new Decoder<>() {
       @Override
diff --git a/src/main/java/eu/mulk/jgvariant/core/Value.java b/src/main/java/eu/mulk/jgvariant/core/Value.java
index 969f240..54c0b79 100644
--- a/src/main/java/eu/mulk/jgvariant/core/Value.java
+++ b/src/main/java/eu/mulk/jgvariant/core/Value.java
@@ -3,33 +3,110 @@
 import java.util.List;
 import java.util.Optional;
 
-/** A value representable by the GVariant serialization format. */
+/**
+ * A value representable by the <a href="https://docs.gtk.org/glib/struct.Variant.html">GVariant</a>
+ * serialization format.
+ *
+ * <p>{@link Value} is a sum type (sealed interface) that represents a GVariant value. Its subtypes
+ * represent the different types of values that GVariant supports.
+ *
+ * @see Decoder
+ */
 public sealed interface Value {
 
-  // Composite types
+  /**
+   * A homogeneous sequence of GVariant values.
+   *
+   * <p>Arrays of fixed width (i.e. of values of fixed size) are represented in a similar way to
+   * plain C arrays. Arrays of variable width require additional space for padding and framing.
+   *
+   * <p>Heterogeneous sequences are represented by {@code Array<Variant>}.
+   *
+   * @param <T> the type of the elements of the array.
+   * @see Decoder#ofArray
+   */
   record Array<T extends Value>(List<T> values) implements Value {}
 
+  /**
+   * A value that is either present or absent.
+   *
+   * @param <T> the contained type.
+   * @see Decoder#ofMaybe
+   */
   record Maybe<T extends Value>(Optional<T> value) implements Value {}
 
+  /**
+   * A tuple of values of fixed types.
+   *
+   * <p>GVariant structures are represented as {@link Record} types. For example, a two-element
+   * structure consisting of a string and an int can be modelled as follows:
+   *
+   * <pre>{@code
+   * record TestRecord(Str s, Int32 i) {}
+   * var testStruct = new Structure<>(new TestRecord(new Str("hello"), new Int32(123));
+   * }</pre>
+   *
+   * @param <T> the {@link Record} type that represents the components of the structure.
+   * @see Decoder#ofStructure
+   */
   record Structure<T extends Record>(T values) implements Value {}
 
+  /**
+   * A dynamically typed box that can hold a single value of any GVariant type.
+   *
+   * @see Decoder#ofVariant
+   */
   record Variant(Class<? extends Value> type, Value value) implements Value {}
 
-  // Primitive types
+  /**
+   * Either true or false.
+   *
+   * @see Decoder#ofBool()
+   */
   record Bool(boolean value) implements Value {
     static Bool TRUE = new Bool(true);
     static Bool FALSE = new Bool(false);
   }
 
+  /**
+   * A {@code byte}-sized integer.
+   *
+   * @see Decoder#ofInt8()
+   */
   record Int8(byte value) implements Value {}
 
+  /**
+   * A {@code short}-sized integer.
+   *
+   * @see Decoder#ofInt16()
+   */
   record Int16(short value) implements Value {}
 
+  /**
+   * An {@code int}-sized integer.
+   *
+   * @see Decoder#ofInt32()
+   */
   record Int32(int value) implements Value {}
 
+  /**
+   * A {@code long}-sized integer.
+   *
+   * @see Decoder#ofInt64()
+   */
   record Int64(long value) implements Value {}
 
+  /**
+   * A double-precision floating point number.
+   *
+   * @see Decoder#ofFloat64()
+   */
   record Float64(double value) implements Value {}
 
+  /**
+   * A character string.
+   *
+   * @see Decoder#ofStr
+   */
   record Str(String value) implements Value {}
 }
diff --git a/src/main/java/eu/mulk/jgvariant/core/package-info.java b/src/main/java/eu/mulk/jgvariant/core/package-info.java
new file mode 100644
index 0000000..dba7a09
--- /dev/null
+++ b/src/main/java/eu/mulk/jgvariant/core/package-info.java
@@ -0,0 +1,32 @@
+/**
+ * Provides {@link eu.mulk.jgvariant.core.Value} and {@link eu.mulk.jgvariant.core.Decoder}, the
+ * foundational classes for <a href="https://docs.gtk.org/glib/struct.Variant.html">GVariant</a>
+ * parsing.
+ *
+ * <p>{@link eu.mulk.jgvariant.core.Value} is a sum type (sealed interface) that represents a
+ * GVariant value. Its subtypes represent the different types of values that GVariant supports.
+ *
+ * <p>Instances of {@link eu.mulk.jgvariant.core.Decoder} read a given concrete subtype of {@link
+ * eu.mulk.jgvariant.core.Value} from a {@link java.nio.ByteBuffer}. The class also contains factory
+ * methods to create those instances.
+ *
+ * <p><strong>Example</strong>
+ *
+ * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
+ * {@code int}, you can use the following code:
+ *
+ * <pre>{@code
+ * record ExampleRecord(Value.Str s, Value.Int32 i) {}
+ *
+ * var decoder =
+ *   Decoder.ofArray(
+ *     Decoder.ofStructure(
+ *       ExampleRecord.class,
+ *       Decoder.ofStr(UTF_8),
+ *       Decoder.ofInt32().withByteOrder(LITTLE_ENDIAN)));
+ *
+ * byte[] bytes = ...;
+ * Value.Array<Value.Structure<ExampleRecord>> example = decoder.decode(ByteBuffer.wrap(bytes));
+ * }</pre>
+ */
+package eu.mulk.jgvariant.core;
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 8880c0b..403cf1f 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,5 +1,11 @@
+/**
+ * Provides a parser for the <a href="https://docs.gtk.org/glib/struct.Variant.html">GVariant</a>
+ * serialization format.
+ *
+ * <p>The {@link eu.mulk.jgvariant.core} package contains the {@link eu.mulk.jgvariant.core.Value}
+ * and {@link eu.mulk.jgvariant.core.Decoder} types. which form the foundation of this library.
+ */
 module eu.mulk.jgvariant.core {
-  requires java.base;
   requires com.google.errorprone.annotations;
   requires org.jetbrains.annotations;
 
diff --git a/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java b/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java
index 4deb8bc..13cd398 100644
--- a/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java
+++ b/src/test/java/eu/mulk/jgvariant/core/DecoderTest.java
@@ -41,7 +41,7 @@
   @Test
   void testBooleanArray() {
     var data = new byte[] {0x01, 0x00, 0x00, 0x01, 0x01};
-    var decoder = Decoder.ofArray(Decoder.ofBoolean());
+    var decoder = Decoder.ofArray(Decoder.ofBool());
     assertEquals(
         new Array<>(List.of(Bool.TRUE, Bool.FALSE, Bool.FALSE, Bool.TRUE, Bool.TRUE)),
         decoder.decode(ByteBuffer.wrap(data)));