Merge pull request #43 from rojotek/make-bytes-comparable

Provided a default implementation of the comparable interface in the Bytes class.
diff --git a/bytes/src/main/java/org/apache/tuweni/bytes/Bytes.java b/bytes/src/main/java/org/apache/tuweni/bytes/Bytes.java
index 23561bc..36d00ce 100644
--- a/bytes/src/main/java/org/apache/tuweni/bytes/Bytes.java
+++ b/bytes/src/main/java/org/apache/tuweni/bytes/Bytes.java
@@ -41,7 +41,7 @@
  * specific implementations may be thread-safe. For instance, the value returned by {@link #copy} is guaranteed to be
  * thread-safe as it is immutable.
  */
-public interface Bytes {
+public interface Bytes extends Comparable<Bytes> {
 
   /**
    * The empty value (with 0 bytes).
@@ -1463,4 +1463,22 @@
   default String toBase64String() {
     return Base64.getEncoder().encodeToString(toArrayUnsafe());
   }
+
+  @Override
+  default int compareTo(Bytes b) {
+    checkNotNull(b);
+
+    int sizeCmp = Integer.compare(bitLength(), b.bitLength());
+    if (sizeCmp != 0) {
+      return sizeCmp;
+    }
+
+    for (int i = 0; i < size(); i++) {
+      int cmp = Integer.compare(get(i) & 0xff, b.get(i) & 0xff);
+      if (cmp != 0) {
+        return cmp;
+      }
+    }
+    return 0;
+  }
 }
diff --git a/bytes/src/test/java/org/apache/tuweni/bytes/BytesTest.java b/bytes/src/test/java/org/apache/tuweni/bytes/BytesTest.java
index 3ccd344..6c0c204 100644
--- a/bytes/src/test/java/org/apache/tuweni/bytes/BytesTest.java
+++ b/bytes/src/test/java/org/apache/tuweni/bytes/BytesTest.java
@@ -275,6 +275,27 @@
   }
 
   @Test
+  void compareTo() {
+    assertEquals(1, Bytes.of(0x05).compareTo(Bytes.of(0x01)));
+    assertEquals(1, Bytes.of(0x05).compareTo(Bytes.of(0x01)));
+    assertEquals(1, Bytes.of(0xef).compareTo(Bytes.of(0x01)));
+    assertEquals(1, Bytes.of(0xef).compareTo(Bytes.of(0x00, 0x01)));
+    assertEquals(1, Bytes.of(0x00, 0x00, 0xef).compareTo(Bytes.of(0x00, 0x01)));
+    assertEquals(1, Bytes.of(0x00, 0xef).compareTo(Bytes.of(0x00, 0x00, 0x01)));
+    assertEquals(1, Bytes.of(0xef, 0xf0).compareTo(Bytes.of(0xff)));
+    assertEquals(1, Bytes.of(0xef, 0xf0).compareTo(Bytes.of(0x01)));
+    assertEquals(1, Bytes.of(0xef, 0xf1).compareTo(Bytes.of(0xef, 0xf0)));
+    assertEquals(1, Bytes.of(0x00, 0x00, 0x01).compareTo(Bytes.of(0x00, 0x00)));
+    assertEquals(0, Bytes.of(0xef, 0xf0).compareTo(Bytes.of(0xef, 0xf0)));
+    assertEquals(-1, Bytes.of(0xef, 0xf0).compareTo(Bytes.of(0xef, 0xf5)));
+    assertEquals(-1, Bytes.of(0xef).compareTo(Bytes.of(0xff)));
+    assertEquals(-1, Bytes.of(0x01).compareTo(Bytes.of(0xff)));
+    assertEquals(-1, Bytes.of(0x01).compareTo(Bytes.of(0x01, 0xff)));
+    assertEquals(-1, Bytes.of(0x00, 0x00, 0x01).compareTo(Bytes.of(0x00, 0x02)));
+    assertEquals(-1, Bytes.of(0x00, 0x01).compareTo(Bytes.of(0x00, 0x00, 0x05)));
+  }
+
+  @Test
   void fromHexStringLenientInvalidInput() {
     Throwable exception = assertThrows(IllegalArgumentException.class, () -> Bytes.fromHexStringLenient("foo"));
     assertEquals("Illegal character 'o' found at index 1 in hex binary representation", exception.getMessage());