Sign in

    moonuuid

    UUIDs for MoonBit: parsing and versions 1 to 8.

    uuid
    guid
    identifier
    rfc9562
    moonbit
    Download zip
    Version
    0.1.1
    License
    Apache-2.0
    Last updated
    1 hour ago
    Downloads
    17

    UUIDs for MoonBit. Read any spelling in use, write the canonical one, and make ids from a name, from a clock, or from random bytes. Time and randomness come in as functions you pass, so the same code runs on every backend and in every test.

    let id = @moonuuid.parse("{C232AB00-9414-11EC-B3C8-9F6BDECED846}")
    id.to_string() // "c232ab00-9414-11ec-b3c8-9f6bdeced846"
    id.version() // Some(1)
    id.node() // 175285648414790

    #Install

    moon add moonbitstack/moonuuid moon add moonbitstack/moonrand # the random source a generator draws from

    #The versions

    VersionMade fromFunctionSorts by time
    1timestamp, clock sequence, nodev1(ticks~, clock_seq~, node~) · gen.v1(node~)
    3MD5 of a namespace and a namev3(space, name)
    4122 random bitsv4(random) · gen.v4()
    5SHA-1 of a namespace and a namev5(space, name)
    6version 1's fields, high time bits firstv6(ticks~, clock_seq~, node~) · gen.v6(node~)✓
    7Unix milliseconds, a counter and random bitsv7(millis~, random) · gen.v7()✓
    8122 bits of your own layoutv8(custom)

    Those are the seven versions RFC 9562 defines. Version 2 is reserved for DCE security and is not generated.

    ticks_of(unix_nanos) turns nanoseconds since 1970 into the 100-nanosecond intervals since 1582 that versions 1 and 6 count. The namespaces are namespace_dns, namespace_url, namespace_oid and namespace_x500; nil and max are all zeros and all ones.

    #Quick start

    // Name-based ids are the same every time.
    let page = @moonuuid.v5(@moonuuid.namespace_url, "https://example.org/")

    // Time-ordered ids from a generator over your clock and randomness.
    let gen = @moonuuid.Generator::new(
    clock=() => now_in_nanoseconds(),
    random=@system.source,
    )
    let row = gen.v7() // sorts in the order made, even within one millisecond

    #Reading and writing

    parse takes the canonical form, any case, with or without hyphens, in braces, or after urn:uuid::

    @moonuuid.parse("6ba7b8109dad11d180b400c04fd430c8")
    @moonuuid.parse("urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8")

    WriteGives
    id.to_string()6ba7b810-9dad-11d1-80b4-00c04fd430c8
    id.hex()6ba7b8109dad11d180b400c04fd430c8
    id.urn()urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8
    id.bytes()the 16 bytes, most significant first
    Json(id)the canonical text; @json.from_json reads any spelling back

    Uuid::of_bytes and Uuid::of_parts(hi, lo) build one from 16 bytes or two 64-bit halves. Identifiers compare, hash and sort by their bytes.

    #Fields

    MethodReturns
    variant()Ncs, Rfc, Microsoft or Future
    version()the version for an RFC 9562 id, else None
    time()100-ns ticks since 1582 for versions 1 and 6, milliseconds since 1970 for version 7
    clock_seq()the 14-bit clock sequence
    node()the 48-bit node

    #The generator

    Generator::new(clock~, random~) keeps what the time-based versions need between calls. clock gives nanoseconds since 1970 and random is a moonrand Source: @system.source from moonbitstack/moonrand/system in a program, a Replay of fixed bytes in a test. A source that cannot give what an id needs is Refused::Random.

    • Version 1 and 6 timestamps never repeat or go back; the clock sequence is random unless you pass one.
    • Version 7 ids made within one millisecond count up with a fresh random tail. If the clock steps back, the next id uses the millisecond after the last one, so the order holds.

    #Errors

    RefusedWhen
    Malformed(at~, reason~)text that is not 32 hexadecimal digits; at is where it went wrong
    Size(want~, got~)bytes of the wrong length
    Random(why)the generator's random source could not give what an id needs

    #Runnable examples

    Two programs in the repository: moon run src/examples/01-ids stands in a clock and a random source, and moon run src/examples/02-tour prints one line per feature.

    #Licence

    Apache-2.0. See LICENSE.

    Refused

    pub(all) suberror Refused {
    Malformed(at~ : Int, reason~ : String)
    Size(want~ : Int, got~ : Int)
    Random(
    Unavailable
    )
    } derive(Eq,
    Debug
    )

    Why text or bytes are not a UUID.
    impl Show for Refused

    Refused::equal

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

    Refused::not_equal

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

    Refused::output

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

    Refused::to_repr

    Refused::to_string

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

    Generator

    pub struct Generator {
    // private fields
    }

    Identifiers from a clock and a source of random bytes the caller supplies, keeping what the time-based versions need between calls: version 1 and 6 timestamps never repeat or go back, and version 7 ids made within one millisecond count up, so they sort in the order made.

    Generator::new

    fn Generator::new(clock~ : () -> Int64, random~ : &
    Source
    ) -> Generator

    clock gives nanoseconds since 1970; random is where the random bits come from: @system.source from moonrand/system in a program, or a Replay of fixed bytes in a test that wants the same ids every run.

    Generator::v1

    fn Generator::v1(self : Generator, node~ : Int64, clock_seq? : Int) -> Uuid raise Refused

    Version 1 with node; the clock sequence is random unless given.

    Generator::v4

    fn Generator::v4(self : Generator) -> Uuid raise Refused

    Version 4 from 16 random bytes.

    Generator::v6

    fn Generator::v6(self : Generator, node~ : Int64, clock_seq? : Int) -> Uuid raise Refused

    Version 6 with node; the clock sequence is random unless given.

    Generator::v7

    fn Generator::v7(self : Generator) -> Uuid raise Refused

    Version 7. Within one millisecond the counter goes up by one with a fresh random tail; when the clock steps back, the millisecond after the last one is used; when the counter runs out, the millisecond moves on.

    Uuid

    pub struct Uuid {
    // private fields
    } derive(Compare, Eq, Hash,
    Debug
    )

    A 128-bit identifier as RFC 9562 lays it out. Compared, hashed and ordered by its bytes, so a sorted list of time-ordered ids is in time order.
    impl Show for Uuid
    impl ToJson for Uuid

    Uuid::bytes

    fn Uuid::bytes(self : Uuid) -> Bytes

    The 16 bytes, most significant first.

    Uuid::clock_seq

    fn Uuid::clock_seq(self : Uuid) -> Int

    The 14-bit clock sequence of versions 1 and 6.

    Uuid::compare

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

    Uuid::equal

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

    Uuid::hash

    fn Uuid::hash(self : Uuid) -> Int

    Uuid::hash_combine

    fn Uuid::hash_combine(Uuid, Hasher) -> Unit

    Uuid::hex

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

    The 32 hexadecimal digits, lowercase, without hyphens.

    Uuid::node

    fn Uuid::node(self : Uuid) -> Int64

    The 48-bit node of versions 1 and 6.

    Uuid::not_equal

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

    Uuid::of_bytes

    fn Uuid::of_bytes(bytes : BytesView) -> Uuid raise Refused

    The identifier from its 16 bytes, most significant first.

    Uuid::of_parts

    fn Uuid::of_parts(hi : UInt64, lo : UInt64) -> Uuid

    The identifier from its high and low 64 bits.

    Uuid::op_ge

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

    Uuid::op_gt

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

    Uuid::op_le

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

    Uuid::op_lt

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

    Uuid::output

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

    Uuid::parts

    fn Uuid::parts(self : Uuid) -> (UInt64, UInt64)

    The high and low 64 bits.

    Uuid::time

    fn Uuid::time(self : Uuid) -> Int64

    The timestamp the fields hold: 100-nanosecond intervals since 1582-10-15 for versions 1 and 6, milliseconds since 1970 for version 7, the version 1 reading of the fields otherwise.

    Uuid::to_json

    fn Uuid::to_json(self : Uuid) -> Json

    Uuid::to_repr

    Uuid::to_string

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

    Uuid::urn

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

    urn:uuid: and the canonical text, as RFC 9562 names an identifier.

    Uuid::variant

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

    The variant its bits name.

    Uuid::version

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

    The version, 1 to 8 for the ones RFC 9562 defines; None when the variant is not RFC 9562's, where the version bits mean nothing.

    Variant

    pub(all) enum Variant {
    Ncs
    Rfc
    Microsoft
    Future
    } derive(Eq,
    Debug
    )

    Who an identifier's variant bits say it belongs to.
    impl Show for Variant

    Variant::equal

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

    Variant::not_equal

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

    Variant::output

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

    Variant::to_repr

    Variant::to_string

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

    gregorian_offset

    let gregorian_offset : Int64

    100-nanosecond intervals between 1582-10-15, where version 1 and 6 timestamps start, and 1970-01-01.

    max

    let max : Uuid

    The max identifier, all ones.

    namespace_dns

    let namespace_dns : Uuid

    The namespaces RFC 9562 assigns for names that are domain names, URLs, ISO OIDs and X.500 distinguished names.

    namespace_oid

    let namespace_oid : Uuid

    namespace_url

    let namespace_url : Uuid

    namespace_x500

    let namespace_x500 : Uuid

    nil

    let nil : Uuid

    The nil identifier, all zeros.

    parse

    fn parse(text : StringView) -> Uuid raise Refused

    Text in any of the spellings in use: canonical, with or without hyphens, in braces, with the urn:uuid: prefix; any case.

    ticks_of

    fn ticks_of(unix_nanos : Int64) -> Int64

    A version 1 or 6 timestamp from nanoseconds since 1970.
    fn v1(ticks~ : Int64, clock_seq~ : Int, node~ : Int64) -> Uuid

    Time-based: a 60-bit timestamp from ticks_of, a 14-bit clock sequence and a 48-bit node, laid out with the low time bits first.
    fn v3(space : Uuid, name : StringView) -> Uuid

    Name-based with MD5: the same namespace and name always give the same identifier. The name is hashed as UTF-8.
    fn v4(random : BytesView) -> Uuid raise Refused

    Random: 122 of the 16 bytes given are kept.
    fn v5(space : Uuid, name : StringView) -> Uuid

    Name-based with SHA-1, preferred over version 3.
    fn v6(ticks~ : Int64, clock_seq~ : Int, node~ : Int64) -> Uuid

    Version 1's fields with the timestamp's high bits first, so the identifiers sort in time order.
    fn v7(millis~ : Int64, random : BytesView) -> Uuid raise Refused

    Milliseconds since 1970 in the top 48 bits, then 74 bits from the 10 random bytes given: a 42-bit counter whose top bit starts clear, so a generator can count up within a millisecond, and 32 random bits.
    fn v8(custom : BytesView) -> Uuid raise Refused

    Custom: 122 bits of the 16 bytes given, laid out as the caller likes; only version and variant are written over.