Consistency, Docs, and QOL Improvements (#12)
All checks were successful
/ Build and Release Library (push) Successful in 1m17s
All checks were successful
/ Build and Release Library (push) Successful in 1m17s
- Fixed consistency around `()` use. - Added `toBytes()` and `fromBytes(Array[Byte])`. - Added missing ScalaDoc. - Updated tests. - Updated all dependencies to latest. Reviewed-on: #12
This commit is contained in:
parent
4370ed80b2
commit
d0dd5c3833
7 changed files with 90 additions and 33 deletions
|
@ -1,9 +1,9 @@
|
||||||
# gs-uuid
|
# gs-uuid
|
||||||
|
|
||||||
[GS Open Source](https://garrity.co/oss.html) |
|
[GS Open Source](https://garrity.co/oss.html) |
|
||||||
[License (MIT)](./LICENSE)
|
[License (Apache 2.0)](./LICENSE)
|
||||||
|
|
||||||
UUID's for Scala 3 with generation based on JUG, and serialization based on code
|
UUIDs for Scala 3 with generation based on JUG, and serialization based on code
|
||||||
from Jackson Databind. The only dependency is JUG, whereas the relevant Jackson
|
from Jackson Databind. The only dependency is JUG, whereas the relevant Jackson
|
||||||
code is copied to this implementation (and slightly modified).
|
code is copied to this implementation (and slightly modified).
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
val scala3: String = "3.4.1"
|
val scala3: String = "3.4.2"
|
||||||
|
|
||||||
ThisBuild / scalaVersion := scala3
|
ThisBuild / scalaVersion := scala3
|
||||||
ThisBuild / versionScheme := Some("semver-spec")
|
ThisBuild / versionScheme := Some("semver-spec")
|
||||||
|
@ -14,7 +14,7 @@ val sharedSettings = Seq(
|
||||||
|
|
||||||
lazy val testSettings = Seq(
|
lazy val testSettings = Seq(
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"org.scalameta" %% "munit" % "1.0.0-M10" % Test
|
"org.scalameta" %% "munit" % "1.0.0" % Test
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,6 +25,6 @@ lazy val `gs-uuid` = project
|
||||||
.settings(name := s"${gsProjectName.value}-v${semVerMajor.value}")
|
.settings(name := s"${gsProjectName.value}-v${semVerMajor.value}")
|
||||||
.settings(
|
.settings(
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"com.fasterxml.uuid" % "java-uuid-generator" % "4.1.1"
|
"com.fasterxml.uuid" % "java-uuid-generator" % "5.1.0"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
sbt.version=1.9.9
|
sbt.version=1.10.1
|
||||||
|
|
|
@ -28,6 +28,6 @@ externalResolvers := Seq(
|
||||||
"Garrity Software Releases" at "https://maven.garrity.co/gs"
|
"Garrity Software Releases" at "https://maven.garrity.co/gs"
|
||||||
)
|
)
|
||||||
|
|
||||||
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.11")
|
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.1.0")
|
||||||
addSbtPlugin("gs" % "sbt-garrity-software" % "0.3.0")
|
addSbtPlugin("gs" % "sbt-garrity-software" % "0.3.0")
|
||||||
addSbtPlugin("gs" % "sbt-gs-semver" % "0.3.0")
|
addSbtPlugin("gs" % "sbt-gs-semver" % "0.3.0")
|
||||||
|
|
|
@ -5,9 +5,9 @@ import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UUID serialization and deserialization. This is a direct copy of Jackson
|
* UUID serialization and deserialization. This is a direct copy of Jackson
|
||||||
* Databind (also under the Apache 2.0 license at time of writing) with
|
* Databind (under the Apache 2.0 license at time of writing) with extremely
|
||||||
* extremely minor modifications to remove dashes from the output and to
|
* minor modifications to remove dashes from the output and to likewise support
|
||||||
* likewise support parsing with/without dashes.
|
* parsing with/without dashes.
|
||||||
*/
|
*/
|
||||||
public final class UUIDFormat {
|
public final class UUIDFormat {
|
||||||
private UUIDFormat() {}
|
private UUIDFormat() {}
|
||||||
|
|
|
@ -16,19 +16,17 @@ import com.fasterxml.uuid.Generators
|
||||||
*
|
*
|
||||||
* ## Serialization
|
* ## Serialization
|
||||||
*
|
*
|
||||||
* This library uses a custom variant of the JDK 17 implementation that removes
|
* This library supports the following representations:
|
||||||
* dashes from the output and is likewise capable of parsing those values.
|
|
||||||
*
|
*
|
||||||
* {{{
|
* - Hexadecimal string without dashes
|
||||||
* val example: UUID = UUID(java.util.UUID.randomUUID())
|
* - Byte array
|
||||||
* val serialized = example.str() // or example.withoutDashes()
|
*
|
||||||
* // example value = 899efa6f40ed45189efa6f40ed9518ed
|
* Serialization code is based on Jackson Databind (Apache 2.0).
|
||||||
* }}}
|
|
||||||
*/
|
*/
|
||||||
opaque type UUID = java.util.UUID
|
opaque type UUID = java.util.UUID
|
||||||
|
|
||||||
object UUID:
|
object UUID:
|
||||||
/** Express any `java.util.UUID` as a Meager UUID.
|
/** Express any `java.util.UUID` as a GS UUID.
|
||||||
*
|
*
|
||||||
* @param uuid
|
* @param uuid
|
||||||
* The input UUID.
|
* The input UUID.
|
||||||
|
@ -37,6 +35,21 @@ object UUID:
|
||||||
*/
|
*/
|
||||||
def apply(uuid: java.util.UUID): UUID = uuid
|
def apply(uuid: java.util.UUID): UUID = uuid
|
||||||
|
|
||||||
|
/** Parse a byte array as a [[UUID]].
|
||||||
|
*
|
||||||
|
* See `toBytes()` for the inverse of this function.
|
||||||
|
*
|
||||||
|
* @param bytes
|
||||||
|
* The array of bytes to parse.
|
||||||
|
* @return
|
||||||
|
* The new [[UUID]], or `None` if the bytes do not represent a valid UUID.
|
||||||
|
*/
|
||||||
|
def fromBytes(bytes: Array[Byte]): Option[UUID] =
|
||||||
|
scala.util
|
||||||
|
.Try(UUIDFormat.fromBytes(bytes))
|
||||||
|
.map(uuid => Some(apply(uuid)))
|
||||||
|
.getOrElse(None)
|
||||||
|
|
||||||
given CanEqual[UUID, UUID] = CanEqual.derived
|
given CanEqual[UUID, UUID] = CanEqual.derived
|
||||||
|
|
||||||
/** Generate a new UUID.
|
/** Generate a new UUID.
|
||||||
|
@ -62,6 +75,14 @@ object UUID:
|
||||||
*/
|
*/
|
||||||
def parse(str: String): Option[UUID] = fromString(str)
|
def parse(str: String): Option[UUID] = fromString(str)
|
||||||
|
|
||||||
|
/** Parse the given string as a UUID.
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* The UUID, which is expected to be in a hexadecimal format with no
|
||||||
|
* dashes.
|
||||||
|
* @return
|
||||||
|
* The parsed UUID value, or `None` if the value does not represent a UUID.
|
||||||
|
*/
|
||||||
def fromString(str: String): Option[UUID] =
|
def fromString(str: String): Option[UUID] =
|
||||||
scala.util
|
scala.util
|
||||||
.Try(UUIDFormat.fromHex(str))
|
.Try(UUIDFormat.fromHex(str))
|
||||||
|
@ -69,16 +90,39 @@ object UUID:
|
||||||
.getOrElse(None)
|
.getOrElse(None)
|
||||||
|
|
||||||
extension (uid: UUID)
|
extension (uid: UUID)
|
||||||
def toUUID: java.util.UUID = uid
|
/** @return
|
||||||
|
* The underlying `java.util.UUID`.
|
||||||
|
*/
|
||||||
|
def toUUID(): java.util.UUID = uid
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* The byte array representation of this UUID.
|
||||||
|
*/
|
||||||
|
def toBytes(): Array[Byte] = UUIDFormat.toBytes(uid)
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* Hexadecimal string representation of this UUID, without dashes.
|
||||||
|
*/
|
||||||
def str(): String = withoutDashes()
|
def str(): String = withoutDashes()
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* Hexadecimal string representation of this UUID, without dashes.
|
||||||
|
*/
|
||||||
def withoutDashes(): String = UUIDFormat.toHex(uid)
|
def withoutDashes(): String = UUIDFormat.toHex(uid)
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* The least significant bits of this UUID.
|
||||||
|
*/
|
||||||
def lsb(): Long = uid.getLeastSignificantBits()
|
def lsb(): Long = uid.getLeastSignificantBits()
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* The most significant bits of this UUID.
|
||||||
|
*/
|
||||||
def msb(): Long = uid.getMostSignificantBits()
|
def msb(): Long = uid.getMostSignificantBits()
|
||||||
|
|
||||||
|
/** @return
|
||||||
|
* `true` if this UUID is `0`, `false` otherwise.
|
||||||
|
*/
|
||||||
def isZero(): Boolean = lsb() == 0L && msb() == 0L
|
def isZero(): Boolean = lsb() == 0L && msb() == 0L
|
||||||
|
|
||||||
/** Type class for UUID generation.
|
/** Type class for UUID generation.
|
||||||
|
@ -91,11 +135,11 @@ object UUID:
|
||||||
object Generator:
|
object Generator:
|
||||||
/** Instantiate a new Type 4 generator.
|
/** Instantiate a new Type 4 generator.
|
||||||
*/
|
*/
|
||||||
def version4: Generator = new Version4
|
def version4(): Generator = new Version4
|
||||||
|
|
||||||
/** Instantiate a new Type 7 generator.
|
/** Instantiate a new Type 7 generator.
|
||||||
*/
|
*/
|
||||||
def version7: Generator = new Version7
|
def version7(): Generator = new Version7
|
||||||
|
|
||||||
/** Type 4 (Random) implementation of a UUID generator.
|
/** Type 4 (Random) implementation of a UUID generator.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package gs.uuid.v0
|
package gs.uuid.v0
|
||||||
|
|
||||||
class UUIDTests extends munit.FunSuite:
|
class UUIDTests extends munit.FunSuite:
|
||||||
private val v4 = UUID.Generator.version4
|
private val v4 = UUID.Generator.version4()
|
||||||
private val v7 = UUID.Generator.version7
|
private val v7 = UUID.Generator.version7()
|
||||||
given CanEqual[java.util.UUID, java.util.UUID] = CanEqual.derived
|
given CanEqual[java.util.UUID, java.util.UUID] = CanEqual.derived
|
||||||
|
|
||||||
test(
|
test(
|
||||||
|
@ -11,7 +11,7 @@ class UUIDTests extends munit.FunSuite:
|
||||||
val base = v4.next()
|
val base = v4.next()
|
||||||
val str = base.str()
|
val str = base.str()
|
||||||
val parsed = UUID.parse(str)
|
val parsed = UUID.parse(str)
|
||||||
assert(parsed == Some(base))
|
assertEquals(parsed, Some(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
test(
|
test(
|
||||||
|
@ -20,7 +20,7 @@ class UUIDTests extends munit.FunSuite:
|
||||||
val base = v7.next()
|
val base = v7.next()
|
||||||
val str = base.str()
|
val str = base.str()
|
||||||
val parsed = UUID.parse(str)
|
val parsed = UUID.parse(str)
|
||||||
assert(parsed == Some(base))
|
assertEquals(parsed, Some(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
test("should instantiate from any java.util.UUID") {
|
test("should instantiate from any java.util.UUID") {
|
||||||
|
@ -28,18 +28,31 @@ class UUIDTests extends munit.FunSuite:
|
||||||
val base = UUID(raw)
|
val base = UUID(raw)
|
||||||
val str = base.str()
|
val str = base.str()
|
||||||
val parsed = UUID.fromString(str)
|
val parsed = UUID.fromString(str)
|
||||||
assert(parsed == Some(base))
|
assertEquals(parsed, Some(base))
|
||||||
assert(parsed.map(_.toUUID) == Some(raw))
|
assertEquals(parsed.map(_.toUUID()), Some(raw))
|
||||||
}
|
}
|
||||||
|
|
||||||
test("should successfully parse a UUID with dashes") {
|
test("should successfully parse a UUID with dashes") {
|
||||||
val base = java.util.UUID.randomUUID()
|
val base = java.util.UUID.randomUUID()
|
||||||
assert(UUID.parse(base.toString()) == Some(UUID(base)))
|
assertEquals(UUID.parse(base.toString()), Some(UUID(base)))
|
||||||
}
|
}
|
||||||
|
|
||||||
test("should fail to parse a non-hex string") {
|
test("should fail to parse a non-hex string") {
|
||||||
val input = "ghijklmnoped45189efa6f40ed9518ed"
|
val input = "ghijklmnoped45189efa6f40ed9518ed"
|
||||||
assert(UUID.parse(input) == None)
|
assertEquals(UUID.parse(input), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("should round trip to/from a byte array") {
|
||||||
|
given UUID.Generator = v7
|
||||||
|
val base = UUID.generate()
|
||||||
|
val bytes = base.toBytes()
|
||||||
|
val parsed = UUID.fromBytes(bytes)
|
||||||
|
assertEquals(parsed, Some(base))
|
||||||
|
}
|
||||||
|
|
||||||
|
test("should fail to parse an invalid byte array") {
|
||||||
|
val bytes = Array[Byte](1)
|
||||||
|
assertEquals(UUID.fromBytes(bytes), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("should generate using an available type class instance") {
|
test("should generate using an available type class instance") {
|
||||||
|
@ -47,14 +60,14 @@ class UUIDTests extends munit.FunSuite:
|
||||||
val base = doGen
|
val base = doGen
|
||||||
val str = base.str()
|
val str = base.str()
|
||||||
val parsed = UUID.parse(str)
|
val parsed = UUID.parse(str)
|
||||||
assert(parsed == Some(base))
|
assertEquals(parsed, Some(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
test("should return lsb, msb, and if the UUID is zero") {
|
test("should return lsb, msb, and if the UUID is zero") {
|
||||||
val uuid = UUID.parse("00000000-0000-0000-0000-000000000000")
|
val uuid = UUID.parse("00000000-0000-0000-0000-000000000000")
|
||||||
assert(uuid.map(_.lsb()) == Some(0L))
|
assertEquals(uuid.map(_.lsb()), Some(0L))
|
||||||
assert(uuid.map(_.msb()) == Some(0L))
|
assertEquals(uuid.map(_.msb()), Some(0L))
|
||||||
assert(uuid.map(_.isZero()) == Some(true))
|
assertEquals(uuid.map(_.isZero()), Some(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def doGen(
|
private def doGen(
|
||||||
|
|
Loading…
Add table
Reference in a new issue