01Install
Add the package, then import it where you use it. The module is
moonbitstack/moonuuid, and the import brings it in as
@moonuuid.
moon add moonbitstack/moonuuidimport {
"moonbitstack/moonuuid",
}02Read one
parse takes text and returns a Uuid. Text that is not an
identifier comes back as a Refused, so a function that parses has to say
what it does with that. fn main raise lets the refusal out.
fn main raise {
let id = @moonuuid.parse("c232ab00-9414-11ec-b3c8-9f6bdeced846")
println(id)
}c232ab00-9414-11ec-b3c8-9f6bdeced84603Every spelling
Hyphens are optional. Case does not matter. Braces and the
urn:uuid: prefix are set aside before the digits are read.
fn main raise {
for text in [
"c232ab00-9414-11ec-b3c8-9f6bdeced846",
"C232AB00941411ECB3C89F6BDECED846",
"{C232AB00-9414-11EC-B3C8-9F6BDECED846}",
"urn:uuid:c232ab00-9414-11ec-b3c8-9f6bdeced846",
] {
println(@moonuuid.parse(text))
}
}c232ab00-9414-11ec-b3c8-9f6bdeced846
c232ab00-9414-11ec-b3c8-9f6bdeced846
c232ab00-9414-11ec-b3c8-9f6bdeced846
c232ab00-9414-11ec-b3c8-9f6bdeced84604Write it back
to_string gives the canonical form. hex drops the
hyphens. urn adds the prefix. All three write lowercase.
fn main raise {
let id = @moonuuid.parse("c232ab00-9414-11ec-b3c8-9f6bdeced846")
println(id.to_string())
println(id.hex())
println(id.urn())
}c232ab00-9414-11ec-b3c8-9f6bdeced846
c232ab00941411ecb3c89f6bdeced846
urn:uuid:c232ab00-9414-11ec-b3c8-9f6bdeced84605Look inside
An identifier answers with the fields its bits name. time is
100-nanosecond intervals since 1582 for versions 1 and 6, and milliseconds since
1970 for version 7. version is None when the variant is not
RFC 9562's, where the version bits mean nothing.
fn main raise {
let id = @moonuuid.parse("c232ab00-9414-11ec-b3c8-9f6bdeced846")
println(id.version()) // Some(1)
println(id.variant()) // Rfc
println(id.time()) // 138648505420000000
println(id.clock_seq()) // 13256
println(id.node()) // 175285648414790
}Some(1)
Rfc
138648505420000000
13256
17528564841479006A clock and a random source
The library never reaches for the clock or for randomness.
Generator::new takes a clock that gives nanoseconds since 1970 and a
random source, a moonrand Source: @system.source from
moonrand/system in a program. It keeps what the time-based versions need
between calls. Here the clock is fixed and the source replays fixed bytes, so every
run prints the same lines.
fn main raise {
let gen = @moonuuid.Generator::new(
clock=() => 1_761_350_400_000_000_000L,
random=@moonrand.Replay::new(Bytes::makei(64, i => (i * 37 + 11).to_byte())),
)
println(gen.v4())
}0b30557a-9fc4-490e-b358-7da2c7ec1136fn main raise {
let gen = @moonuuid.Generator::new(
clock=() => 1_761_350_400_000_000_000L,
random=@moonrand.Replay::new(Bytes::makei(64, i => (i * 37 + 11).to_byte())),
)
for _ in 0..<3 {
println(gen.v7())
}
}019a18aa-3800-74c1-957a-9fc4e90e3358
019a18aa-3800-74c1-957a-9fc57da2c7ec
019a18aa-3800-74c1-957a-9fc611365b80Within one millisecond the counter goes up with a fresh random tail. A clock that steps back uses the millisecond after the last one, so the order holds.
07Time-based, field by field
ticks_of turns nanoseconds since 1970 into the 100-nanosecond
intervals since 1582 that versions 1 and 6 count. Version 6 lays the timestamp's
high bits first, so identifiers sort in the order they were made; version 1 keeps
the older layout.
fn main {
let ticks = @moonuuid.ticks_of(1_761_350_400_000_000_000L)
println(@moonuuid.v1(ticks~, clock_seq=0x2A3B, node=0x001A2B3C4D5EL))
println(@moonuuid.v6(ticks~, clock_seq=0x2A3B, node=0x001A2B3C4D5EL))
}8cacc000-b135-11f0-aa3b-001a2b3c4d5e
1f0b1358-cacc-6000-aa3b-001a2b3c4d5e08From a name
Versions 3 and 5 hash a namespace and a name: MD5 for version 3, SHA-1 for version 5. The same pair always gives the same identifier. The name is hashed as UTF-8, so text in any language is fine.
fn main {
println(@moonuuid.v5(@moonuuid.namespace_url, "https://example.org/"))
println(@moonuuid.v5(@moonuuid.namespace_dns, "李雷"))
}527dda32-a0de-5105-a042-cb475b5f7d11
97ce974b-b58a-513c-994e-06af9b649d7fnamespace_dns, namespace_url, namespace_oid and namespace_x500 are the four namespaces RFC 9562 assigns.
09Your own layout
Version 8 keeps 122 bits of the sixteen bytes you pass and writes only the version and variant over them, so the layout is yours.
fn main raise {
let custom = Bytes::makei(16, i => (i * 17 + 3).to_byte())
println(@moonuuid.v8(custom))
}03142536-4758-897a-8b9c-adbecfe0f10210When it refuses
Refused says what was wrong. Malformed points at the
character that stopped the parse; Size gives the two lengths.
fn main {
try {
ignore(@moonuuid.parse("not-a-uuid"))
} catch {
e => println(e)
}
try {
ignore(@moonuuid.v4(Bytes::make(3, 0)))
} catch {
e => println(e)
}
}"n" is not a hexadecimal digit at 0
16 bytes wanted, 3 given11JSON
An identifier writes itself as the canonical string, and reads any spelling
back. This section needs moonbitlang/core/json in the package's
imports.
fn main raise {
let id = @moonuuid.parse("c232ab00-9414-11ec-b3c8-9f6bdeced846")
let j = Json(id)
println(j.stringify())
let back : @moonuuid.Uuid = @json.from_json(j)
println(back)
}"c232ab00-9414-11ec-b3c8-9f6bdeced846"
c232ab00-9414-11ec-b3c8-9f6bdeced846