uuidm

    Universally unique identifiers (UUIDs) for MoonBit - supports UUID versions 3, 4, 5, 7, and 8 according to RFC 9562

    uuid
    guid
    rfc9562
    Download zip
    Author
    Version
    0.1.3
    License
    ISC
    Last updated
    10 days ago
    Downloads
    75

    #Uuidm — Universally unique identifiers (UUIDs) for MoonBit

    Uuidm is a MoonBit library implementing 128 bits universally unique identifiers (UUIDs) versions 3, 4, 5, 7, and 8 according to RFC 9562.

    This is a port of the original OCaml uuidm library by Daniel Bünzli.

    #Features

    • UUID v3: Name-based UUIDs using MD5 hashing
    • UUID v4: Random or pseudo-random UUIDs
    • UUID v5: Name-based UUIDs using SHA-1 hashing
    • UUID v7: Time-ordered UUIDs with random component
    • UUID v8: Custom format UUIDs
    • String conversion: To/from standard UUID string representations
    • Standard namespaces: DNS, URL, OID, and X.500 namespaces
    • No external dependencies: Pure MoonBit implementation

    #Installation

    This library is designed to work with the MoonBit compiler. Add it to your moon.mod.json:

    { "name": "your-project", "version": "0.1.0", "deps": { "uuidm": "0.1.0" } }

    #Quick Start

    // Generate a random UUID (version 4)
    let uuid = v4()
    println(uuid.to_string()) // e.g., "550e8400-e29b-41d4-a716-446655440000"

    // Generate time-ordered UUID (version 7)
    let time_uuid = v7()
    println(time_uuid.to_string())

    // Generate name-based UUID (version 5)
    let name_uuid = v5(ns_dns, "example.com")
    println(name_uuid.to_string())

    // Parse UUID from string
    match from_string("550e8400-e29b-41d4-a716-446655440000") {
    Some(uuid) => println("Parsed: " + uuid.to_string())
    None => println("Invalid UUID")
    }

    #API Reference

    #Core Types

    // UUID type
    struct Uuid {
    bytes : FixedArray[Byte]
    }

    // UUID variants
    enum Variant {
    Ncs | Rfc9562 | Microsoft | Reserved
    }

    // UUID versions
    enum Version {
    V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8
    }

    #UUID Generation

    // Version 4 (Random)
    pub fn v4() -> Uuid
    pub fn v4_bulk(count : Int) -> Array[Uuid]

    // Version 3 (Name-based with MD5)
    pub fn v3(namespace : Uuid, name : String) -> Uuid
    pub fn v3_dns(name : String) -> Uuid
    pub fn v3_url(name : String) -> Uuid

    // Version 5 (Name-based with SHA-1)
    pub fn v5(namespace : Uuid, name : String) -> Uuid
    pub fn v5_dns(name : String) -> Uuid
    pub fn v5_url(name : String) -> Uuid

    // Version 7 (Time-ordered)
    pub fn v7() -> Uuid
    pub fn v7_with_timestamp(timestamp_ms : Int64) -> Uuid
    pub fn v7_sequence(count : Int) -> Array[Uuid]

    // Version 8 (Custom)
    pub fn v8(custom_data : FixedArray[Byte]) -> Uuid
    pub fn v8_counter(counter : Int64, node_id : Int, application_id : Int) -> Uuid
    pub fn v8_mixed(timestamp_ms : Int64, custom_suffix : Int) -> Uuid

    #String Conversion

    // Convert to string
    pub fn to_string(uuid : Uuid) -> String // With hyphens
    pub fn to_string_simple(uuid : Uuid) -> String // Without hyphens
    pub fn to_urn(uuid : Uuid) -> String // URN format

    // Parse from string
    pub fn from_string(s : String) -> Uuid? // Safe parsing
    pub fn from_string_exn(s : String) -> Uuid // Panics on error
    pub fn from_urn(s : String) -> Uuid? // Parse URN format

    #UUID Properties

    // Get UUID properties
    pub fn variant(uuid : Uuid) -> Variant
    pub fn version(uuid : Uuid) -> Option[Version]
    pub fn bytes(uuid : Uuid) -> FixedArray[Byte]

    // Special UUIDs
    pub fn nil() -> Uuid // All zeros
    pub fn max() -> Uuid // All ones
    pub fn is_nil(uuid : Uuid) -> Bool
    pub fn is_max(uuid : Uuid) -> Bool

    #Standard Namespaces

    pub let ns_dns : Uuid // DNS namespace
    pub let ns_url : Uuid // URL namespace
    pub let ns_oid : Uuid // OID namespace
    pub let ns_x500 : Uuid // X.500 namespace

    #Examples

    #Name-based UUIDs

    // Using predefined namespaces
    let dns_uuid = v5_dns("example.com")
    let url_uuid = v5_url("https://example.com/path")

    // Using custom namespace
    let custom_ns = v4() // or any other UUID
    let custom_uuid = v5(custom_ns, "my-resource")

    // Version 3 vs Version 5 (different hash algorithms)
    let v3_uuid = v3_dns("example.com")
    let v5_uuid = v5_dns("example.com")
    // These will be different UUIDs

    #Time-ordered UUIDs

    // Generate sequence of time-ordered UUIDs
    let sequence = v7_sequence(5)
    // These will be in chronological order

    // Extract timestamp from v7 UUID
    match extract_timestamp(v7_uuid) {
    Some(timestamp) => println("Created at: " + timestamp.to_string())
    None => println("Not a v7 UUID")
    }

    #Custom UUIDs (Version 8)

    // Counter-based UUID
    let counter_uuid = v8_counter(12345L, 999, 888)

    // Mixed timestamp + custom data
    let mixed_uuid = v8_mixed(current_timestamp_ms(), 0x123456)

    // Fully custom
    let custom_data : FixedArray[Byte] = FixedArray::make(16, 0x42b)
    let custom_uuid = v8(custom_data)

    #Testing

    The library includes comprehensive tests:

    moon test

    #Implementation Notes

    • Cryptographic hashing: The MD5 and SHA-1 implementations are simplified for demonstration. In production, you may want to use proper cryptographic libraries.
    • Random number generation: Uses a simple linear congruential generator. For cryptographic applications, consider using a cryptographically secure random number generator.
    • Performance: This implementation prioritizes clarity and correctness over performance optimization.

    #Compliance

    This library implements UUIDs according to RFC 9562 (formerly RFC 4122). It supports:

    • ✅ UUID version 3 (name-based, MD5)
    • ✅ UUID version 4 (random)
    • ✅ UUID version 5 (name-based, SHA-1)
    • ✅ UUID version 7 (time-ordered)
    • ✅ UUID version 8 (custom)
    • ✅ Standard string representations
    • ✅ Standard namespaces

    #License

    This library is distributed under the ISC license, same as the original OCaml implementation.

    #Contributing

    Contributions are welcome! Please ensure any changes include appropriate tests and documentation.

    #Acknowledgments

    This is a port of the excellent uuidm library by Daniel Bünzli. The original design and implementation patterns have been adapted for MoonBit while maintaining compatibility with RFC 9562.

    Md5

    type Md5

    Basic MD5 implementation for UUID v3 This is a simplified implementation for demonstration

    Md5::new

    fn Md5::new() -> Md5

    Create a new MD5 hasher

    SimpleRng

    type SimpleRng

    Simple linear congruential generator for generating random bytes This is a basic implementation - in production you might want to use a better quality random number generator or system entropy

    SimpleRng::fill_bytes

    fn SimpleRng::fill_bytes(self : SimpleRng, bytes : FixedArray[Byte]) -> Unit

    Fill an array with random bytes

    SimpleRng::new

    fn SimpleRng::new(seed : Int64) -> SimpleRng

    Create a new random number generator with a seed

    SimpleRng::new_with_time

    fn SimpleRng::new_with_time() -> SimpleRng

    Create a new random number generator with current time as seed

    SimpleRng::next_byte

    fn SimpleRng::next_byte(self : SimpleRng) -> Byte

    Generate a random byte

    SimpleRng::next_int64

    fn SimpleRng::next_int64(self : SimpleRng) -> Int64

    Generate the next random 64-bit integer

    Uuid

    type Uuid derive(Compare, Eq)

    A UUID is represented as 16 bytes (128 bits)
    impl Show for Uuid

    Uuid::bytes

    fn Uuid::bytes(self : Uuid) -> FixedArray[Byte]

    Get the raw bytes of the UUID

    Uuid::compare

    fn Uuid::compare(Uuid, Uuid) -> Int

    Keep Compare usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::equal

    fn Uuid::equal(Uuid, Uuid) -> Bool

    Keep Eq usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::from_bytes

    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

    Create a UUID from individual byte values

    Uuid::is_max

    fn Uuid::is_max(self : Uuid) -> Bool

    Check if the UUID is max (all ones)

    Uuid::is_nil

    fn Uuid::is_nil(self : Uuid) -> Bool

    Check if the UUID is nil (all zeros)

    Uuid::new

    fn Uuid::new(bytes : FixedArray[Byte]) -> Uuid

    Create a new UUID from 16 bytes

    Uuid::not_equal

    fn Uuid::not_equal(x : Uuid, y : Uuid) -> Bool

    Keep Eq usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::op_ge

    fn Uuid::op_ge(x : Uuid, y : Uuid) -> Bool

    Keep Compare usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::op_gt

    fn Uuid::op_gt(x : Uuid, y : Uuid) -> Bool

    Keep Compare usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::op_le

    fn Uuid::op_le(x : Uuid, y : Uuid) -> Bool

    Keep Compare usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::op_lt

    fn Uuid::op_lt(x : Uuid, y : Uuid) -> Bool

    Keep Compare usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::output

    fn Uuid::output(self : Uuid, logger : &Logger) -> Unit

    Keep Show::output usable through dot syntax on Uuid (previously provided by the deprecated implicit impl promotion).

    Uuid::to_string

    fn Uuid::to_string(self : Uuid) -> String

    Convert UUID to string representation with hyphens Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    Uuid::to_string_simple

    fn Uuid::to_string_simple(self : Uuid) -> String

    Convert UUID to string representation without hyphens

    Uuid::to_urn

    fn Uuid::to_urn(self : Uuid) -> String

    Convert UUID to URN string representation Format: urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

    Uuid::variant

    fn Uuid::variant(self : Uuid) -> Variant

    Get the variant of the UUID

    Uuid::version

    fn Uuid::version(self : Uuid) -> Version?

    Get the version of the UUID (only meaningful for RFC 9562 variant)

    Variant

    UUID variant as defined in RFC 9562
    impl Show for Variant

    Variant::equal

    fn Variant::equal(Variant, Variant) -> Bool

    Keep Eq usable through dot syntax on Variant (previously provided by the deprecated implicit impl promotion).

    Variant::not_equal

    fn Variant::not_equal(x : Variant, y : Variant) -> Bool

    Keep Eq usable through dot syntax on Variant (previously provided by the deprecated implicit impl promotion).

    Variant::output

    fn Variant::output(self : Variant, logger : &Logger) -> Unit

    Keep Show usable through dot syntax on Variant (previously provided by the deprecated implicit impl promotion).

    Variant::to_repr

    Keep Debug::to_repr usable through dot syntax on Variant (previously provided by the deprecated implicit impl promotion).

    Variant::to_string

    fn Variant::to_string(self : Variant) -> String

    Keep Show usable through dot syntax on Variant (previously provided by the deprecated implicit impl promotion).

    Version

    UUID version as defined in RFC 9562
    impl Show for Version

    Version::equal

    fn Version::equal(Version, Version) -> Bool

    Keep Eq usable through dot syntax on Version (previously provided by the deprecated implicit impl promotion).

    Version::not_equal

    fn Version::not_equal(x : Version, y : Version) -> Bool

    Keep Eq usable through dot syntax on Version (previously provided by the deprecated implicit impl promotion).

    Version::output

    fn Version::output(self : Version, logger : &Logger) -> Unit

    Keep Show usable through dot syntax on Version (previously provided by the deprecated implicit impl promotion).

    Version::to_repr

    Keep Debug::to_repr usable through dot syntax on Version (previously provided by the deprecated implicit impl promotion).

    Version::to_string

    fn Version::to_string(self : Version) -> String

    Keep Show usable through dot syntax on Version (previously provided by the deprecated implicit impl promotion).

    combine_namespace_and_name

    fn combine_namespace_and_name(ns : Uuid, name : String) -> FixedArray[Byte]

    Combine ns UUID and name for hashing

    demo

    fn demo() -> String

    Example usage and demo function

    demo_uuid_library

    fn demo_uuid_library() -> Unit

    extract_custom_data

    fn extract_custom_data(uuid : Uuid) -> FixedArray[Byte]?

    Extract custom data from a version 8 UUID (excluding version/variant bits)

    extract_timestamp

    fn extract_timestamp(uuid : Uuid) -> Int64?

    Extract timestamp from a version 7 UUID

    from_string

    fn from_string(s : String) -> Uuid?

    Parse UUID from string representation Accepts both hyphenated and non-hyphenated formats

    from_string_exn

    fn from_string_exn(s : String) -> Uuid

    Parse UUID from string, panics on invalid input

    from_urn

    fn from_urn(s : String) -> Uuid?

    Parse UUID from URN string representation

    from_urn_exn

    fn from_urn_exn(s : String) -> Uuid

    Parse UUID from URN string, panics on invalid input

    max

    fn max() -> Uuid

    Generate the max UUID (all ones)

    md5_hash

    fn md5_hash(data : FixedArray[Byte]) -> FixedArray[Byte]

    Simplified MD5 hash function Note: This is a basic implementation for demonstration purposes In production, you would use a proper cryptographic library

    nil

    fn nil() -> Uuid

    Generate the nil UUID (all zeros)

    ns_dns

    let ns_dns : Uuid

    DNS namespace UUID (6ba7b810-9dad-11d1-80b4-00c04fd430c8)

    ns_oid

    let ns_oid : Uuid

    OID namespace UUID (6ba7b812-9dad-11d1-80b4-00c04fd430c8)

    ns_url

    let ns_url : Uuid

    URL namespace UUID (6ba7b811-9dad-11d1-80b4-00c04fd430c8)

    ns_x500

    let ns_x500 : Uuid

    X500 namespace UUID (6ba7b814-9dad-11d1-80b4-00c04fd430c8)

    random_bytes

    fn random_bytes(count : Int) -> FixedArray[Byte]

    Generate random bytes using a new RNG instance

    sha1_hash

    fn sha1_hash(data : FixedArray[Byte]) -> FixedArray[Byte]

    Basic SHA-1 implementation for UUID v5 This is a simplified implementation for demonstration

    string_to_bytes

    fn string_to_bytes(s : String) -> FixedArray[Byte]

    Convert string to UTF-8 bytes for hashing (RFC 4122/9562 compliant)

    UTF-8 Encoding Implementation

    This implementation now properly converts strings to UTF-8 bytes as required by RFC 4122/9562 for UUID v3/v5 generation. This matches the behavior of reference implementations in JavaScript/Node.js, Python, etc.

    UTF-8 Encoding Rules:

    • ASCII (U+0000-U+007F): 1 byte
    • U+0080-U+07FF: 2 bytes
    • U+0800-U+FFFF: 3 bytes (includes most Chinese characters)
    • U+10000-U+10FFFF: 4 bytes

    Examples:

    • "hello" → [0x68, 0x65, 0x6C, 0x6C, 0x6F] (5 bytes)
    • "中" (U+4E2D) → [0xE4, 0xB8, 0xAD] (3 bytes)
    • "国" (U+56FD) → [0xE5, 0x9B, 0xBD] (3 bytes)
    • "中国" → [0xE4, 0xB8, 0xAD, 0xE5, 0x9B, 0xBD] (6 bytes)

    This now matches JavaScript's new TextEncoder().encode(string) behavior.

    Spec Compliance Achievement! 🎉

    This implementation is now RFC 4122/9562 compliant for UTF-8 encoding! UUIDs generated with Chinese characters should now match reference implementations in JavaScript/Node.js, Python, and other spec-compliant libraries (assuming the same MD5/SHA-1 implementation).
    fn v3(ns : Uuid, name : String) -> Uuid

    Generate a UUID version 3 (name-based using MD5)

    v3_dns

    fn v3_dns(name : String) -> Uuid

    Convenience function to generate v3 UUID with DNS namespace

    v3_oid

    fn v3_oid(name : String) -> Uuid

    Convenience function to generate v3 UUID with OID namespace

    v3_url

    fn v3_url(name : String) -> Uuid

    Convenience function to generate v3 UUID with URL namespace

    v3_x500

    fn v3_x500(name : String) -> Uuid

    Convenience function to generate v3 UUID with X500 namespace
    fn v4() -> Uuid

    Generate a random UUID (version 4) Uses random or pseudo-random numbers for all bits except version and variant

    v4_bulk

    fn v4_bulk(count : Int) -> Array[Uuid]

    Generate multiple random UUIDs

    v4_with_rng

    fn v4_with_rng(rng : SimpleRng) -> Uuid

    Generate a random UUID using a specific random number generator
    fn v5(ns : Uuid, name : String) -> Uuid

    Generate a UUID version 5 (name-based using SHA-1)

    v5_dns

    fn v5_dns(name : String) -> Uuid

    Convenience function to generate v5 UUID with DNS namespace

    v5_oid

    fn v5_oid(name : String) -> Uuid

    Convenience function to generate v5 UUID with OID namespace

    v5_url

    fn v5_url(name : String) -> Uuid

    Convenience function to generate v5 UUID with URL namespace

    v5_x500

    fn v5_x500(name : String) -> Uuid

    Convenience function to generate v5 UUID with X500 namespace
    fn v7() -> Uuid

    Generate a time-ordered UUID (version 7) Format: 48-bit timestamp + 12-bit random + 2-bit variant + 62-bit random

    v7_sequence

    fn v7_sequence(count : Int) -> Array[Uuid]

    Generate multiple time-ordered UUIDs ensuring monotonicity

    v7_with_timestamp

    fn v7_with_timestamp(timestamp_ms : Int64) -> Uuid

    Generate a time-ordered UUID with specific timestamp
    fn v8(custom_data : FixedArray[Byte]) -> Uuid

    Generate a custom UUID (version 8) The caller is responsible for providing the custom data

    v8_counter

    fn v8_counter(counter : Int64, node_id : Int, application_id : Int) -> Uuid

    Generate a custom UUID with application-specific structure Example: counter-based UUID with specific formatting

    v8_from_int128

    fn v8_from_int128(high : Int64, low : Int64) -> Uuid

    Generate a custom UUID from a 128-bit integer

    v8_mixed

    fn v8_mixed(timestamp_ms : Int64, custom_suffix : Int) -> Uuid

    Generate a custom UUID with mixed content (timestamp + random + custom)