-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add name based UUIDv5 implementation (#197)
Add name based UUIDv5 implementation
- Loading branch information
Showing
5 changed files
with
95 additions
and
1 deletion.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
modules/core/.js/src/main/scala/io/chrisdavenport/fuuid/PlatformSpecificMethods.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package io.chrisdavenport.fuuid | ||
|
||
import cats.ApplicativeError | ||
|
||
object PlatformSpecificMethods { | ||
def nameBased[F[_]]: (FUUID, String, ApplicativeError[F, Throwable]) => F[FUUID] = (_, _, AE) => | ||
AE.raiseError(new NotImplementedError("Name based UUIDs are not supported for Scala.js")) | ||
} |
50 changes: 50 additions & 0 deletions
50
modules/core/.jvm/src/main/scala/io/chrisdavenport/fuuid/PlatformSpecificMethods.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package io.chrisdavenport.fuuid | ||
|
||
import cats._ | ||
import cats.implicits._ | ||
import java.util.UUID | ||
import java.security.MessageDigest | ||
|
||
object PlatformSpecificMethods { | ||
def nameBased[F[_]]: (FUUID, String, ApplicativeError[F, Throwable]) => F[FUUID] = (namespace, name, AE) => | ||
Either | ||
.catchNonFatal( | ||
MessageDigest | ||
.getInstance("SHA-1") | ||
.digest( | ||
uuidBytes(namespace) ++ | ||
name.getBytes("UTF-8") | ||
) | ||
) | ||
.map { bs => | ||
val cs = bs.take(16) // Truncate 160 bits (20 bytes) SHA-1 to fit into our 128 bits of space | ||
cs(6) = (cs(6) & 0x0f).asInstanceOf[Byte] /* clear version */ | ||
cs(6) = (cs(6) | 0x50).asInstanceOf[Byte] /* set to version 5, SHA1 UUID */ | ||
cs(8) = (cs(8) & 0x3f).asInstanceOf[Byte] /* clear variant */ | ||
cs(8) = (cs(8) | 0x80).asInstanceOf[Byte] /* set to IETF variant */ | ||
cs | ||
} | ||
.flatMap( | ||
bs => | ||
Either.catchNonFatal { | ||
val bb = java.nio.ByteBuffer.allocate(java.lang.Long.BYTES) | ||
bb.put(bs, 0, 8) | ||
bb.flip | ||
val most = bb.getLong | ||
bb.flip | ||
bb.put(bs, 8, 8) | ||
bb.flip | ||
val least = bb.getLong | ||
FUUID.fromUUID(new UUID(most, least)) | ||
} | ||
) | ||
.liftTo[F](AE) | ||
|
||
private def uuidBytes(fuuid: FUUID): Array[Byte] = { | ||
val bb = java.nio.ByteBuffer.allocate(2 * java.lang.Long.BYTES) | ||
val uuid = FUUID.Unsafe.toUUID(fuuid) | ||
bb.putLong(uuid.getMostSignificantBits) | ||
bb.putLong(uuid.getLeastSignificantBits) | ||
bb.array | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
modules/core/.jvm/src/test/scala/io/chrisdavenport/fuuid/FUUIDJvmSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package io.chrisdavenport.fuuid | ||
|
||
import cats.effect.IO | ||
import org.specs2._ | ||
|
||
class FUUIDJvmSpec extends mutable.Specification with ScalaCheck { | ||
|
||
"FUUID.nameBased" should { | ||
"produce a valid UUID" in { | ||
(for { | ||
namespace <- FUUID.randomFUUID[IO] | ||
namebased <- FUUID.nameBased[IO](namespace, "What up yo!") | ||
parsed <- FUUID.fromStringF[IO](namebased.toString) | ||
} yield parsed) | ||
.attempt | ||
.unsafeRunSync | ||
.isRight must_=== true | ||
} | ||
|
||
"conform to an example" in { | ||
val namespace = FUUID.fromStringF[IO]("dc79a6bc-de3c-5bc7-a877-712bea708d8f").unsafeRunSync() | ||
val name = "What up yo!" | ||
|
||
val expected = FUUID.fromStringF[IO]("1cce4593-d217-5b33-be0d-2e81462e79d3").unsafeRunSync() | ||
|
||
FUUID.nameBased[IO](namespace, name).unsafeRunSync must_=== expected | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters