/// Universally Unique Identifiers (UUIDs) for MoonBit
///
/// This library implements UUID versions 3, 4, 5, 7, and 8 according to RFC 9562.
/// UUIDs are 128-bit identifiers that are unique across both space and time.
///|
/// A UUID is represented as 16 bytes (128 bits)
struct Uuid(FixedArray[Byte]) derive(Eq, Compare)
///|
/// Show the UUID as a string which conforms to the UUID format (8-4-4-4-12)
/// # Example
/// ```
/// let uuid = Uuid::from_bytes(b'\x7F', b'\xAA', b'\x02', b'\x93', b'\x7F', b'\xAA', b'\x32', b'\x93', b'\xBF', b'\xAA', b'\x02', b'\x93', b'\x7F', b'\xAA', b'\x02', b'\x93')
/// inspect(uuid, content="7faa0293-7faa-3293-bfaa-02937faa0293")
/// ```
pub impl Show for Uuid with output(self, logger) {
logger.write_string(self.to_string())
}
///|
/// UUID variant as defined in RFC 9562
enum Variant {
/// Reserved for NCS compatibility (0b0xx)
Ncs
/// RFC 9562 variant (0b10x)
Rfc9562
/// Reserved for Microsoft compatibility (0b110)
Microsoft
/// Reserved for future definition (0b111)
Reserved
} derive(Eq, Show)
///|
/// UUID version as defined in RFC 9562
enum Version {
/// Version 1: Time-based (deprecated)
V1
/// Version 2: DCE Security (deprecated)
V2
/// Version 3: Name-based using MD5 hashing
V3
/// Version 4: Random or pseudo-random
V4
/// Version 5: Name-based using SHA-1 hashing
V5
/// Version 6: Reordered time-based (draft)
V6
/// Version 7: Time-ordered random
V7
/// Version 8: Custom format
V8
} derive(Eq, Show)
///|
/// Create a new UUID from 16 bytes
pub fn Uuid::new(bytes : FixedArray[Byte]) -> Uuid {
if bytes.length() != 16 {
abort("UUID must be exactly 16 bytes")
}
Uuid(bytes)
}
///|
/// Create a UUID from individual byte values
pub fn Uuid::from_bytes(
b0 : Byte,
b1 : Byte,
b2 : Byte,
b3 : Byte,
b4 : Byte,
b5 : Byte,
b6 : Byte,
b7 : Byte,
b8 : Byte,
b9 : Byte,
b10 : Byte,
b11 : Byte,
b12 : Byte,
b13 : Byte,
b14 : Byte,
b15 : Byte,
) -> Uuid {
let bytes : FixedArray[Byte] = FixedArray::make(16, b'\x00')
bytes[0] = b0
bytes[1] = b1
bytes[2] = b2
bytes[3] = b3
bytes[4] = b4
bytes[5] = b5
bytes[6] = b6
bytes[7] = b7
bytes[8] = b8
bytes[9] = b9
bytes[10] = b10
bytes[11] = b11
bytes[12] = b12
bytes[13] = b13
bytes[14] = b14
bytes[15] = b15
Uuid(bytes)
}
///|
/// Get the raw bytes of the UUID
pub fn Uuid::bytes(self : Uuid) -> FixedArray[Byte] {
self.0
}
///|
/// Get the variant of the UUID
pub fn Uuid::variant(self : Uuid) -> Variant {
let bits = self.0[8].to_int() >> 6
match bits {
0 | 1 => Variant::Ncs
2 | 3 => Variant::Rfc9562
6 => Variant::Microsoft
7 => Variant::Reserved
_ => Variant::Reserved // Should not happen
}
}
///|
/// Get the version of the UUID (only meaningful for RFC 9562 variant)
pub fn Uuid::version(self : Uuid) -> Version? {
if self.variant() != Variant::Rfc9562 {
None
} else {
let version_bits = self.0[6].to_int() >> 4
match version_bits {
1 => Some(Version::V1)
2 => Some(Version::V2)
3 => Some(Version::V3)
4 => Some(Version::V4)
5 => Some(Version::V5)
6 => Some(Version::V6)
7 => Some(Version::V7)
8 => Some(Version::V8)
_ => None
}
}
}
///|
/// Set the variant and version bits for an RFC 9562 UUID
fn set_variant_and_version(bytes : FixedArray[Byte], version : Version) -> Unit {
// Set variant bits (bits 6-7 of octet 8) to 10 (RFC 9562)
bytes[8] = bytes[8].to_int().land(0x3F).lor(0x80).to_byte()
// Set version bits (bits 4-7 of octet 6)
let version_int = match version {
Version::V1 => 1
Version::V2 => 2
Version::V3 => 3
Version::V4 => 4
Version::V5 => 5
Version::V6 => 6
Version::V7 => 7
Version::V8 => 8
}
bytes[6] = bytes[6].to_int().land(0x0F).lor(version_int << 4).to_byte()
}
///|
/// Generate the nil UUID (all zeros)
pub fn nil() -> Uuid {
let bytes : FixedArray[Byte] = FixedArray::make(16, b'\x00')
Uuid(bytes)
}
///|
/// Check if the UUID is nil (all zeros)
pub fn Uuid::is_nil(self : Uuid) -> Bool {
for i = 0; i < 16; i = i + 1 {
if self.0[i] != b'\x00' {
return false
}
}
true
}
///|
/// Generate the max UUID (all ones)
pub fn max() -> Uuid {
let bytes : FixedArray[Byte] = FixedArray::make(16, b'\xFF')
Uuid(bytes)
}
///|
/// Check if the UUID is max (all ones)
pub fn Uuid::is_max(self : Uuid) -> Bool {
for i = 0; i < 16; i = i + 1 {
if self.0[i] != b'\xFF' {
return false
}
}
true
}