Created
August 5, 2020 18:46
-
-
Save andersonsp/b60ba52cb42fc21d2cf3f12c31efe8fe to your computer and use it in GitHub Desktop.
Simple Binary ULID implementation in 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
package io.andersonsp.ulid | |
import scala.util.{Failure, Success, Try} | |
import java.security.SecureRandom | |
// The components are encoded as 16 octets. Each component is encoded with the Most Significant Byte first (network byte order). | |
// 0 1 2 3 | |
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
// | 32_bit_uint_time_high | | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
// | 16_bit_uint_time_low | 16_bit_uint_random | | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
// | 32_bit_uint_random | | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
// | 32_bit_uint_random | | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
class ULIDGenerator { | |
private val random = SecureRandom.getInstance("NativePRNGNonBlocking") | |
def generate: ULID = { | |
val time = System.currentTimeMillis() | |
ULID((time << 16) | (random.nextLong & 0xFFFF), random.nextLong) | |
} | |
} | |
case class ULID(msb: Long, lsb: Long) extends Ordered[ULID] { | |
def toBytes: Array[Byte] = java.nio.ByteBuffer.allocate(ULID.Length).putLong(msb).putLong(lsb).array() | |
def timestamp: Long = msb >>> 16 | |
override def compare(that: ULID): Int = { | |
if (msb == that.msb) { | |
lsb.compareTo(that.lsb) | |
} else { | |
msb.compareTo(that.msb) | |
} | |
} | |
} | |
object ULID { | |
val Length = 16 | |
def fromBytes(bytes: Array[Byte]): Try[ULID] = { | |
if (bytes.length != Length) { | |
Failure(new IllegalArgumentException("Binary ULID must be 16 bytes long")) | |
} else { | |
val buf = java.nio.ByteBuffer.wrap(bytes) | |
val msb = buf.getLong | |
val lsb = buf.getLong | |
Success(ULID(msb, lsb)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment