For Development HEAD DRAFTSearch (procedure/syntax/module):

12.26 data.ulid - Universally unique lexicographically sortable identifier

Module: data.ulid

This module implements ULID (https://github.com/ulid/spec), a UUID-like unique identifier that can be sortable in chronological order and has slightly more compact string representation.

(define gen-ulid (make-ulid-generator))

(gen-ulid) ⇒ #<ulid 01G70P3EWJT28VPQ12NTFFDSZ1>

(ulid->string (gen-ulid)) ⇒ "01G70P3Y72TQ1HYY90G8TJSY07"

NB: The new version of UUID RFC (RFC9562) contains a UUID version 7 which has similar monotonic property of ULID, except the compact notation. See rfc.uuid - UUID, for the details.

Function: make-ulid-generator :optional random-source

Creates and returns a generator that yields a fresh ULID object every time it is called. The optional random-source argument is a SRFI-27 random source (see srfi.27 - Sources of Random Bits) to be used for the random part of ULID. When omitted, an internal random source is used.

To guarantee uniqueness and monotonicity, a ULID generator needs to keep internal state. If you want to share the generator among multiple threads, you need to manage your own lock. Keeping the generator private in one thread eliminates the need of mutex (however, monotonicity is only guaranteed within each generator).

A ULID consists of 48bit timestamp field (milliseconds since Unix epoch) and 80bit randomness field. The randomness field are generated randomly if it is the first ULID within the timestamp. If more than one ULID needs to be generated in a millisecond window, the subsequent ULID gets randomness field incremented from the previous ULID, so that the chronological order is maintained.

The ULID spec says if the randomness field overflows because so many ULIDs are generated within a millisecond, it is an error. Such scenario is very unlikely but can occur. In our implementation, however, we wait for the next millisecond boundary in case we ran out randomness field, so the generator never yields an error.

Function: ulid? obj

Returns #t iff obj is an ULID object.

Function: ulid-timestamp ulid

Returns the timestamp part of ulid (48bits) as an exact integer.

Function: ulid-randomness ulid

Returns the randomess part of ulid (80bits) as an exact integer.

Function: ulid=? ulid1 ulid2

Returns true if two ULIDs are equivalent.

Function: ulid<? ulid1 ulid2

Returns true if ulid1 precedes ulid2. If both ULIDs are created from the same generator, this means ulid1 is created chronologically before ulid2. If they are created from different generators, the chronological order is not guaranteed, but the discrepancy only occurs when two ULIDs are created at the same timestamp in millisecond resolution.

Function: ulid-hash ulid

Returns a hash value of ulid in a nonnegative exact integer.

Variable: ulid-comparator

Bound to a comparator suitable to compare and hash ULIDs.

Function: ulid->bytevector ulid
Function: bytevector->ulid uv

Covvert between ulid and a u8vector of length 16. Bits are packed in big-endian order (first 8 bits of timestamp to first byte, and so on).

Function: ulid->integer ulid
Function: integer->ulid n

Convert between ulid and an exact nonnegative integer up to 128bit.

Function: ulid->string ulid
Function: string->ulid str

Convert ulid to a string of Base32 representation; the digits are 0123456789ABCDEFGHJKMNPQRSTVWXYZ (I, L, O, and U are excluded to avoid confusion). Length of the string is always 26.

ulid->string always use uppercase characters; on the other hand, string->ulid allows both lowercase and uppercase characters.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT