| Title: | Universally Unique Identifiers, Their Encodings and Their Kin |
|---|---|
| Description: | Parses, validates, inspects and generates universally unique identifiers (UUIDs) of every version defined by RFC 9562 <doi:10.17487/RFC9562>, and re-encodes them in alternative text forms such as Crockford base32, base36, base58, base62, base64url, Proquint and Niceware words. The same functions read the fields and creation time of related identifier formats: Universally Unique Lexicographically Sortable Identifiers (ULID), TypeID, Universally Unique Prefixed Lexicographically Sortable Identifiers (UPID), SCRU128 and SCRU64 (Sortable, Clock and Random number-based Unique identifiers), K-Sortable Unique Identifiers (KSUID), Snowflake, XID, 'MongoDB' ObjectId, NanoID, Cuid2, Sqids and content identifiers (CID). Detection never assumes a format that the input does not prove. Identifiers are generated from the operating system's entropy source, never from R's random number generator. No other package is needed at run time. |
| Authors: | Pedro Baltazar [aut, cre, cph], yan [cph] (Author of the Niceware word list, compiled into src/zuid_tables.c), Sqids [cph] (Authors of the Sqids blocklist, compiled into src/zuid_tables.c) |
| Maintainer: | Pedro Baltazar <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-11-12 10:10:03 UTC |
| Source: | https://github.com/pedrobtz/zuid |
id_convert() moves values between formats that hold the same bits:
"uuid", "ulid", "typeid" and "upid" (128 bits), and "xid" and
"objectid" (96 bits, laid out alike). The bytes are kept and the text is
rewritten.
id_convert(x, to, prefix = NULL)id_convert(x, to, prefix = NULL)
x |
A zuid vector. |
to |
The format to convert to. |
prefix |
For |
A UUID becomes a TypeID under prefix, and a TypeID becomes a UUID by
dropping it.
A UPID becomes a UUID as the reference converts it, keeping the bits.
A ULID and a UUID convert by reinterpreting the bits. id_fields() then
reports what the bits say: most ULIDs read as UUIDs of the "future"
variant, and a UUID read as a ULID has its first 48 bits as a time, which
is meaningful for version 7 only.
Any other pair is a zuid_convert_error: the target would need a value
the source does not have. To change a UUID's text form, use
id_format().
A zuid vector of format to.
x <- id_parse("01890a5d-ac96-774b-bcce-b302099a8057", "uuid") t <- id_convert(x, "typeid", prefix = "user") t id_convert(t, "uuid") id_convert(x, "ulid")x <- id_parse("01890a5d-ac96-774b-bcce-b302099a8057", "uuid") t <- id_convert(x, "typeid", prefix = "user") t id_convert(t, "uuid") id_convert(x, "ulid")
id_detect() names the format of each element, or gives NA when the
evidence does not settle it. Detection never guesses:
id_detect(x, hint = NULL, layout = NULL)id_detect(x, hint = NULL, layout = NULL)
x |
A character vector. |
hint |
|
layout |
An |
Without a hint, only structured formats are tried, since an encoding
or a syntactic format (NanoID, Cuid2, Sqids) matches any string over its
alphabet. A UUID written in Crockford base32 is textually a ULID, and
the ULID is what is detected; id_parse(x, "uuid", form = "base32") is
how to say otherwise.
When exactly one format passes at the "structure" level, it is the
answer. When several pass, the answer is NA, and the candidates
attribute lists them. A 26-character lowercase Crockford string, for
one, is a ULID or a TypeID without a prefix.
A Snowflake is considered only under a Snowflake layout, since every
layout reads the digits differently. A SCRU64 is listed among the
candidates, but chosen only under id_layout("scru64", node_bits = ).
hint restricts the formats tried to those named, and is how a
syntactic format or an encoding can be detected at all.
Formats are recognised in their canonical text, with their default alphabets.
A character vector of formats, NA where none or several fit,
with the attribute candidates: a list of the formats each element
passes, structured formats first.
id_detect(c( "018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "01ARZ3NDEKTSV4RRFFQ69G5FAV", "01arz3ndektsv4rrffq69g5fav", "not an id" )) id_detect("01arz3ndektsv4rrffq69g5fav", hint = "typeid") id_detect("175928847299117063", layout = id_layout("discord"))id_detect(c( "018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "01ARZ3NDEKTSV4RRFFQ69G5FAV", "01arz3ndektsv4rrffq69g5fav", "not an id" )) id_detect("01arz3ndektsv4rrffq69g5fav", hint = "typeid") id_detect("175928847299117063", layout = id_layout("discord"))
id_encode() writes bytes of any length as text in a form, and
id_decode() reads them back. A UUID's text forms are the 16-byte case:
id_format(x, form) is id_encode(id_bytes(x), form).
id_encode(bytes, form, alphabet = NULL, sep = "-") id_decode(text, form, alphabet = NULL, width = NULL)id_encode(bytes, form, alphabet = NULL, sep = "-") id_decode(text, form, alphabet = NULL, width = NULL)
bytes |
A raw vector (one element), a list of raw vectors ( |
form |
The form. |
alphabet |
For |
sep |
The separator between units for |
text |
A character vector. |
width |
|
Each form writes what the mainstream Go and Python libraries write, so text made elsewhere decodes here and the other way round:
"hex": lowercase hexadecimal. Decoding takes either case and ignores
hyphens.
"base32": Crockford's alphabet, with the spare bits in front as zero
bits, as ULID and TypeID do. Sixteen bytes give 26 characters starting
0 to 7, so a UUID in this form is textually a ULID. Uppercase, and
either case on input; the letters I, L, O and U are rejected.
"base32rfc", "base32hex": RFC 4648 sections 6 and 7, with the spare
bits at the end and no padding. Decoding also takes = padding.
"base36": 0-9a-z, fixed width; 16 bytes are Uuid25's 25 characters.
"base58": base58btc. Each leading zero byte is one 1, so the length
varies, as in Bitcoin and Go's and Python's base58.
"base62", "base62sort": 0-9A-Za-z, fixed width, padded with 0;
sorts as the bytes do. The two names are one form.
"base64url": RFC 4648 section 5, no padding. Decoding also takes =
padding.
"base64sort": base64url's bits in the IETF draft's alphabet, in ASCII
order, so it sorts as the bytes do.
"alphabet": the caller's symbols, most significant digit first, fixed
width, padded with the first symbol. The default is ShortUUID's 57
symbols, as ShortUUID 1.0 and later write them.
"proquint": each 16 bits as five pronounceable letters.
"words": each 16 bits as a Niceware word. The Niceware list was not
checked for offensive words, and some text in this form may offend.
The fixed-width forms ("base32", "base36", "base62", "alphabet")
write the digits the byte count needs, so the length gives the byte count
back. "proquint" and "words" take an even number of bytes, and their
decoding ignores case and any non-letter between units.
id_encode(): a character vector, NA where bytes is NULL.
id_decode(): a list of raw vectors, with NULL where text is NA
or not text of the form.
b <- as.raw(c(0xf8, 0x1d, 0x4f, 0xae)) id_encode(b, "base58") id_decode("7R3N7TW", "base32") x <- id_parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6", "uuid") id_encode(id_bytes(x), "base62") id_format(x, "proquint") id_encode(id_bytes(x), "alphabet", alphabet = "0123456789")b <- as.raw(c(0xf8, 0x1d, 0x4f, 0xae)) id_encode(b, "base58") id_decode("7R3N7TW", "base32") x <- id_parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6", "uuid") id_encode(id_bytes(x), "base62") id_format(x, "proquint") id_encode(id_bytes(x), "alphabet", alphabet = "0123456789")
id_fields() reports what each identifier carries, one row per element.
id_time() returns its time field alone, and id_version() its version.
id_fields(x) id_time(x, class = c("POSIXct", "ms")) id_version(x)id_fields(x) id_time(x, class = c("POSIXct", "ms")) id_version(x)
x |
A zuid vector from |
class |
For |
For a UUID, the fields depend on the version and are read only when the variant is RFC 9562's:
versions 1 and 6: the time in 100 ns ticks from 1582-10-15, the 14-bit
clock sequence (sequence) and the 48-bit node;
version 4: the 122 random bits;
version 7: the millisecond time and the 74 random bits;
versions 2, 3, 5 and 8: the version only.
A ULID has its millisecond time and 80 random bits. A TypeID has its
UUID's fields and its prefix, "" when it has none. A UPID has its time
in 256 ms units, 64 random bits, its prefix and its version nibble
(6, the reference's "a", is the current one).
A SCRU128 has its millisecond time, counter_hi in node (as hex),
counter_lo in sequence and its 32 entropy bits in random. A SCRU64
has its time at 256 ms, and its node and counter in sequence when it
was parsed with id_layout("scru64", node_bits = ). A KSUID has its time
in seconds and its 128-bit payload in random. An XID has its time in
seconds, its machine id in node, its process and its counter in
sequence; an ObjectId the same, but its middle five bytes are random,
as the current BSON specification makes them. A Snowflake has what its
layout says: the time at the layout's unit and epoch, the node fields in
node as name=value pairs, and the sequence. A CID has its CID
version, its content codec and hash function by multicodec name (or
0x and the code when zuid does not know the name) and its digest as
hex. A Sqid has its numbers. NanoID and Cuid2 have no fields: a Cuid2's
time is hashed in and cannot be read back.
The nil and max UUIDs report versions 0 and 15 and no variant. random
is the random bits joined in order, as hex, left-padded with zero bits to
a whole number of hex digits.
id_fields(): a data frame with columns format, time,
time_unit, version, variant, node, process, sequence,
random, prefix, codec, hash, digest and numbers, NA where
the format or the element has no such field. id_time(): a POSIXct
in UTC or a double. id_version(): an integer vector.
x <- id_parse(c( "018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "c232ab00-9414-11ec-b3c8-9f6bdeced846" ), "uuid") id_fields(x) id_time(x) id_version(x)x <- id_parse(c( "018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "c232ab00-9414-11ec-b3c8-9f6bdeced846" ), "uuid") id_fields(x) id_time(x) id_version(x)
id_format() writes identifiers in their canonical text or another text
form. id_bytes() returns their bytes, and id_from_bytes() reads them
back.
id_format(x, form = NULL) id_bytes(x) id_from_bytes(bytes, format, layout = NULL)id_format(x, form = NULL) id_bytes(x) id_from_bytes(bytes, format, layout = NULL)
x |
A zuid vector from |
form |
A text form of the vector's format (see |
bytes |
A raw matrix with one column per element, a list of raw
vectors ( |
format |
The format the bytes are in. Required. |
layout |
For |
Every encoding of id_encode() is a form of a UUID too: id_format(x, "base62") is id_encode(id_bytes(x), "base62").
id_from_bytes() has no default format: sixteen bytes are not a UUID
until the caller says so.
id_format(): a character vector. id_bytes(): a raw matrix
with the format's width in rows and one column per element, big-endian,
with missing elements as columns of zeros listed in the attribute na.
A CID has no fixed width, so for a CID it is a list of raw vectors
instead, NULL for a missing element. Names become column names, or
list names. id_from_bytes(): a zuid vector, named by the column names
or list names of bytes.
x <- id_parse("018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "uuid") id_format(x, "urn") id_format(x, "compact") id_format(x, "base32") b <- id_bytes(x) b[, 1] id_from_bytes(b, "uuid")x <- id_parse("018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "uuid") id_format(x, "urn") id_format(x, "compact") id_format(x, "base32") b <- id_bytes(x) b[, 1] id_from_bytes(b, "uuid")
The identifier formats zuid knows
id_formats()id_formats()
A data frame with one row per format: its name; its class
(structured, encoding or syntactic); its width in bits; the
length of its canonical text; its alphabet and case rule; the unit and
epoch of its time field; and the text forms id_format() accepts.
id_formats()id_formats()
A layout says how a 64-bit identifier splits into a time, node fields and a sequence. It is data: the time field's bits, unit and epoch, the node fields with their widths in order, the sequence width, and whether the top bit is a sign bit. zuid cannot discover a Snowflake's layout from the number, so its fields are readable only when the layout is given.
id_layout( name = NULL, epoch = NULL, node_bits = NULL, time = NULL, fields = NULL, sequence = NULL, sign_bit = TRUE ) ## S3 method for class 'zuid_layout' print(x, ...) ## S3 method for class 'zuid_layout' format(x, ...)id_layout( name = NULL, epoch = NULL, node_bits = NULL, time = NULL, fields = NULL, sequence = NULL, sign_bit = TRUE ) ## S3 method for class 'zuid_layout' print(x, ...) ## S3 method for class 'zuid_layout' format(x, ...)
name |
A built-in layout, or |
epoch |
For |
node_bits |
For |
time |
For a custom layout, |
fields |
For a custom layout, the node fields as a named list or vector of widths, most significant first. |
sequence |
For a custom layout, the sequence's bits. |
sign_bit |
For a custom layout, whether the top bit is reserved. |
x |
A layout. |
... |
Unused. |
The built-in layouts:
| Name | Time | Node fields | Sequence |
twitter |
41 bits, ms, from 2010-11-04T01:42:54.657Z | datacenter 5, worker 5 |
12 |
discord |
42 bits, ms, from 2015-01-01 | worker 5, process 5 |
12 |
instagram |
41 bits, ms, from 2011-08-24T21:07:01.721Z | shard 13 |
10 |
sonyflake |
39 bits, 10 ms, from epoch |
machine 16, after the sequence |
8 |
scru64 |
39 bits, 256 ms, from 1970 | node of node_bits |
24 - node_bits
|
Twitter, Sonyflake and SCRU64 keep the top bit as a sign bit; Discord and
Instagram use all 64 bits. Sonyflake's reference has changed its default
start time between releases, so epoch is required for it.
A custom layout gives time, fields, sequence and sign_bit. The
bits must add up to 64, or 63 with the sign bit, and each part must have
fewer than 54 bits, so that it reads exactly as a double. The sequence
has at most 31 bits, so that id_fields() returns it as an integer.
A zuid_layout.
id_layout("twitter") id_layout("scru64", node_bits = 8) id_layout( time = list(bits = 41, unit = "ms", epoch = 0), fields = list(worker = 10), sequence = 12 )id_layout("twitter") id_layout("scru64", node_bits = 8) id_layout( time = list(bits = 41, unit = "ms", epoch = 0), fields = list(worker = 10), sequence = 12 )
id_parse() turns text into a zuid vector of one format, holding each
element's canonical text. id_valid() is the vectorised predicate.
id_parse( x, format = NULL, form = NULL, layout = NULL, level = c("structure", "syntax", "strict"), strict = FALSE, alphabet = NULL, min_length = 0 ) id_valid( x, format, form = NULL, layout = NULL, level = c("structure", "syntax", "strict"), alphabet = NULL, min_length = 0 )id_parse( x, format = NULL, form = NULL, layout = NULL, level = c("structure", "syntax", "strict"), strict = FALSE, alphabet = NULL, min_length = 0 ) id_valid( x, format, form = NULL, layout = NULL, level = c("structure", "syntax", "strict"), alphabet = NULL, min_length = 0 )
x |
A character vector. |
format |
The format, such as |
form |
A text form of |
layout |
For |
level |
The validation level elements must reach. |
strict |
If |
alphabet |
For |
min_length |
For |
Validation is cumulative over three levels:
"syntax": the alphabet, length, case rule and separators of the form.
"structure": syntax, and the value's own rules. For a UUID, the variant
bits are the RFC's (10), except for the nil and max UUIDs.
"strict": structure, and the value is one its specification defines.
For a UUID, the version is 1 to 8 (or nil or max), and a time field is
no later than now plus the option zuid.time_tolerance (seconds, one
day by default).
A UUID's canonical text is lowercase and hyphenated. On input, either
case is accepted, and form selects another of the RFC 9562 text forms:
"compact" (32 hex digits), "urn" (urn:uuid: prefix), "braced" or
"uppercase", or one of the encodings of id_encode() over the 16 bytes,
such as "base32", "base58" or "words".
A ULID is 26 Crockford base32 characters, uppercase, either case on
input, starting 0 to 7. A TypeID is a lowercase prefix, _ and 26
lowercase Crockford characters, or the 26 alone; strict asks what it asks
of the UUID. A UPID is four prefix characters, _ and 22 lowercase
characters, as the reference writes them; strict asks for the current
version. SCRU128 is 25 base36 characters and SCRU64 12, lowercase,
either case on input; their reserved timestamps (the first and the last)
pass "syntax" only. A KSUID is 27 base62 characters, case-sensitive,
at most aWgEPTl1tmebfsQzFP4bxwgy80V. Strict also asks that a time is no
later than now plus the tolerance. An XID is 20 lowercase base32hex
characters, an ObjectId 24 hex digits (either case on input) and a
Snowflake 1 to 20 decimal digits without leading zeros. A NanoID is one or
more symbols of its alphabet; a Cuid2 is 2 to 32 of 0-9a-z, and strict
asks that it starts with a letter, as generated ones do. A Sqid is valid
when it decodes and its numbers encode back to it under the alphabet,
min_length and blocklist. A CID is version 0 (Qm and 44 base58btc
characters) or version 1 in one of 17 multibases; structure checks its
varints, and the digest length of a hash function zuid knows. These
formats have one text form each.
id_parse(): a zuid vector, the same length as x, with NA
where an element is missing or fails level. id_valid(): a logical
vector, NA where x is.
x <- id_parse("018F6B1C-2D3E-7A4B-8C5D-6E7F8091A2B3", "uuid") x id_valid(c("018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "nope"), "uuid") id_parse("{018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3}", "uuid", form = "braced")x <- id_parse("018F6B1C-2D3E-7A4B-8C5D-6E7F8091A2B3", "uuid") x id_valid(c("018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3", "nope"), "uuid") id_parse("{018f6b1c-2d3e-7a4b-8c5d-6e7f8091a2b3}", "uuid", form = "braced")
nanoid() generates NanoIDs: size symbols drawn uniformly from
alphabet, by NanoID 6's customRandom(). Random bytes come in batches,
each read from its last byte, and a byte at or above the largest multiple
of the alphabet's size below 256 is rejected, so every symbol is equally
likely. When rejection uses up a batch, another is drawn.
nanoid(n = 1, size = 21, alphabet = NULL, random = NULL) sqids(numbers, alphabet = NULL, min_length = 0, blocklist = NULL)nanoid(n = 1, size = 21, alphabet = NULL, random = NULL) sqids(numbers, alphabet = NULL, min_length = 0, blocklist = NULL)
n |
The number of NanoIDs. |
size |
Symbols per NanoID, 1 to 65536, 21 by default. |
alphabet |
The symbols, or |
random |
For |
numbers |
A numeric vector, or a list of numeric vectors, of whole
numbers from 0 to 2^53 - 1. An element that is |
min_length |
The shortest Sqid, 0 to 255. |
blocklist |
|
sqids() encodes non-negative whole numbers as Sqids, by the
specification's algorithm: the default alphabet and blocklist unless
given, and padded to min_length. A numeric vector gives one Sqid per
number; a list gives one per element, encoding all its numbers. An ID
that contains a blocklisted word is re-encoded with the next offset; when
every offset is blocked, the result is a zuid_encode_error. An element
with no numbers encodes as "", as the specification says, and ""
parses back to no numbers.
A zuid vector.
nanoid(2) nanoid(2, size = 10, alphabet = "0123456789abcdef") sqids(c(1, 2, 3)) sqids(list(c(1, 2, 3)), min_length = 10)nanoid(2) nanoid(2, size = 10, alphabet = "0123456789abcdef") sqids(c(1, 2, 3)) sqids(list(c(1, 2, 3)), min_length = 10)
scru128() generates SCRU128 IDs by the specification's generator:
48 bits of milliseconds, a 24-bit counter_hi renewed once a second, a
24-bit counter_lo renewed each millisecond and incremented within it,
and 32 random bits. Values from one session strictly increase; a counter
overflow moves the timestamp forward instead of waiting.
scru128(n = 1, random = NULL, time = NULL, rollback = c("error", "reset")) scru64( n = 1, node, node_bits, random = NULL, time = NULL, rollback = c("error", "reset") ) ksuid(n = 1, random = NULL, time = NULL)scru128(n = 1, random = NULL, time = NULL, rollback = c("error", "reset")) scru64( n = 1, node, node_bits, random = NULL, time = NULL, rollback = c("error", "reset") ) ksuid(n = 1, random = NULL, time = NULL)
n |
The number of UUIDs. |
random |
|
time |
|
rollback |
What to do when the clock runs back further than the
tolerance: |
node, node_bits
|
The SCRU64 node id and its size in bits, 1 to 23;
the counter gets the other |
scru64() generates SCRU64 IDs for one node, as the reference
generator does: 256 ms ticks, then node in node_bits bits, then a
counter renewed at each tick and incremented within it. node and
node_bits are required, since only the caller can know that no other
generator uses the same node.
ksuid() generates KSUIDs: seconds since 2014-05-13T16:53:20Z and
128 random bits. KSUIDs are not monotonic within a second.
A clock that runs back by up to the option zuid.rollback_tolerance
(seconds, 10 by default) keeps the last timestamp, as both SCRU
specifications recommend. Further back, rollback = "error" raises
zuid_clock_error, so that monotonicity is never silently lost, and
rollback = "reset" restarts the generator at the new time. A counter
overflow that would reach the reserved last timestamp is a
zuid_overflow_error.
SCRU64 keeps one state per node and node_bits, so values for each
node increase however the calls for different nodes interleave. As in
uuid(), a call given both time and random is a pure function of
its arguments.
A zuid vector of n values.
scru128(2) scru64(2, node = 42, node_bits = 8) ksuid(2)scru128(2) scru64(2, node = 42, node_bits = 8) ksuid(2)
ulid() generates ULIDs: 48 bits of milliseconds and 80 random bits.
Values from one session strictly increase, by the specification's rule:
within a millisecond, the random component of the last value plus one.
That overflows only after 2^80 values in one millisecond, which is a
zuid_overflow_error.
ulid(n = 1, random = NULL, time = NULL) typeid(n = 1, prefix, random = NULL, time = NULL) upid(n = 1, prefix, random = NULL, time = NULL)ulid(n = 1, random = NULL, time = NULL) typeid(n = 1, prefix, random = NULL, time = NULL) upid(n = 1, prefix, random = NULL, time = NULL)
n |
The number of UUIDs. |
random |
|
time |
|
prefix |
For |
typeid() generates TypeIDs: a version 7 UUID, as uuid() makes
it, under prefix.
upid() generates UPIDs: 40 bits of time in 256 ms units, 64 random
bits, the prefix and the current version, as the reference does. UPIDs
are not monotonic within 256 ms.
Entropy comes from the operating system, never from R's random number
generator, and the clock rollback rule of uuid() applies to ULIDs.
As there, a call given both time and random is a pure function of its
arguments.
A zuid vector of n values.
ulid(2) typeid(2, "user") upid(2, "user")ulid(2) typeid(2, "user") upid(2, "user")
Generates n UUIDs of a version, version 7 by default, from the
operating system's entropy source and clock. R's random number generator
is never used, so set.seed() does not change the result.
uuid( n = 1, version = 7, namespace = NULL, name = NULL, node = NULL, random = NULL, time = NULL )uuid( n = 1, version = 7, namespace = NULL, name = NULL, node = NULL, random = NULL, time = NULL )
n |
The number of UUIDs. |
version |
1, 4, 6, 7 or 8. |
namespace, name
|
Reserved for the name-based versions 3 and 5. |
node |
For versions 1 and 6, six raw bytes to use as the node instead of the session's random one. |
random |
|
time |
|
Version 7 (the default): 48 bits of milliseconds, a 12-bit counter and 62 random bits. Values from one session strictly increase (RFC 9562 section 6.2, method 1): within a millisecond the counter increments, and when it would overflow the millisecond advances by one.
Version 4: 122 random bits.
Versions 1 and 6: the time in 100 ns ticks, a 14-bit clock sequence and a 48-bit node. The clock sequence and node are random, drawn once per session, and the node has its multicast bit set so it is never mistaken for a hardware address (RFC 9562 section 6.10). Values from one session strictly increase in time.
Version 8: the caller's 122 bits, through random.
A clock that runs back by up to the option zuid.rollback_tolerance
(seconds, 10 by default) keeps generation increasing from the last value.
A time that runs back is treated as the clock is, so within the
tolerance a version 7 value keeps the latest time so far. Further back, version 7 restarts at the new time and versions 1 and 6
increment the clock sequence. Values that would pass the last instant
the time field holds are a zuid_overflow_error.
With both time and random given, a call is a pure function of its
arguments: the same arguments give the same UUIDs, and the session's
monotonic state is neither used nor changed. Values within the call
still increase.
Versions 3 and 5 hash a name and are not generated yet; parsing them works. Version 2 is not generated: RFC 9562 leaves it to DCE Security.
A zuid vector of n UUIDs.
uuid(3) uuid(2, version = 4) uuid(version = 7, time = as.POSIXct("2022-02-22 19:22:22", tz = "UTC"))uuid(3) uuid(2, version = 4) uuid(version = 7, time = as.POSIXct("2022-02-22 19:22:22", tz = "UTC"))
The nil and max UUIDs
uuid_nil() uuid_max()uuid_nil() uuid_max()
A zuid vector of one UUID: all bits zero (uuid_nil()) or all bits
one (uuid_max()).
uuid_nil() uuid_max()uuid_nil() uuid_max()
xid() generates XIDs: seconds since 1970, a 3-byte machine id, a
2-byte process id and a 3-byte counter. The reference derives the machine
id from the host name through MD5; zuid draws three random bytes once per
session instead, and machine takes the reference's bytes when they
matter. The process id is R's, masked to 16 bits. The counter starts at a
random value once per session and increments, wrapping at 2^24.
xid(n = 1, machine = NULL, process = Sys.getpid(), random = NULL, time = NULL) objectid(n = 1, random = NULL, time = NULL) snowflake(n = 1, layout, worker, time = NULL, rollback = c("error", "reset"))xid(n = 1, machine = NULL, process = Sys.getpid(), random = NULL, time = NULL) objectid(n = 1, random = NULL, time = NULL) snowflake(n = 1, layout, worker, time = NULL, rollback = c("error", "reset"))
n |
The number of UUIDs. |
machine |
For |
process |
For |
random |
|
time |
|
layout |
An |
worker |
The node fields' values: one number when the layout has one
node field, else a named list, such as |
rollback |
For |
objectid() generates BSON ObjectIds: seconds, a 5-byte random value
drawn once per session, and a 3-byte counter started at a random value.
snowflake() generates Snowflakes under a layout. worker sets every
node field, since duplicate node ids across machines are what Snowflake
exists to prevent and only the caller can rule them out. The sequence
starts at zero each tick and increments within it; when it overflows,
generation moves to the next tick. One sequence serves every node value
of a layout, so values for different workers interleave without repeats.
A clock back by up to the option zuid.clock_tolerance (seconds, 0.01 by
default) keeps the last tick. Further back, rollback = "error" raises
zuid_clock_error, and rollback = "reset" restarts the layout's
generator at the new time, which may repeat values made before.
A zuid vector of n values.
xid(2) objectid(2) snowflake(2, id_layout("twitter"), list(datacenter = 1, worker = 7))xid(2) objectid(2) snowflake(2, id_layout("twitter"), list(datacenter = 1, worker = 7))
Reports the installed version, the generated tables compiled into it, the entropy source and the monotonic generation state.
zuid_info()zuid_info()
A list with elements:
versionthe package version, as a package_version.
tablesa data frame with one row per generated table: its
name, the upstream repo, commit and path, the file's sha256,
and the number of entries.
entropythe operating-system entropy source in use:
"getrandom", "getentropy", "BCryptGenRandom" or
"arc4random_buf", or "/dev/urandom" once a Linux kernel without
getrandom(2) has fallen back to it.
statethe session's monotonic generation state: the last
version 7 millisecond and counter, the last version 1 and 6 tick
and clock sequence, and the last ULID millisecond, NA before the
first value.
zuid_info()zuid_info()