pub struct Ulid(/* private fields */);ulid only.Expand description
A 128-bit ULID.
Internally stored as 16 big-endian bytes: 6 bytes of millisecond timestamp followed by 10 bytes of randomness.
§Example
use id_forge::ulid::Ulid;
let id = Ulid::new();
assert_eq!(id.to_string().len(), 26);Implementations§
Source§impl Ulid
impl Ulid
Sourcepub const fn nil() -> Self
pub const fn nil() -> Self
The Nil ULID: all 128 bits set to zero.
§Example
use id_forge::ulid::Ulid;
assert_eq!(Ulid::nil().to_string(), "00000000000000000000000000");Sourcepub const fn max() -> Self
pub const fn max() -> Self
The Max ULID: all 128 bits set to one — the largest value the
26-character display can represent (7ZZZ… since the spec
reserves the top two bits of the leading character).
§Example
use id_forge::ulid::Ulid;
assert_eq!(Ulid::max().to_string(), "7ZZZZZZZZZZZZZZZZZZZZZZZZZ");Sourcepub fn new() -> Self
pub fn new() -> Self
Construct a new ULID at the current wall-clock millisecond.
Two ULIDs minted in the same millisecond by the same process are strictly ordered: the second one is the first one’s random suffix plus one. Across milliseconds, the randomness is freshly drawn.
§Example
use id_forge::ulid::Ulid;
let a = Ulid::new();
let b = Ulid::new();
assert!(b > a);Examples found in repository?
7fn main() {
8 let v4 = Uuid::v4();
9 println!("UUID v4: {v4} (version={})", v4.version());
10 println!("UUID v7: {}", Uuid::v7());
11 println!("UUID nil: {}", Uuid::nil());
12
13 let a = Ulid::new();
14 let b = Ulid::new();
15 println!("ULID a: {a}");
16 println!("ULID b: {b} (monotonic: {})", b > a);
17
18 let gen = Snowflake::new(1);
19 let sf = gen.next_id();
20 let (ts_offset, worker, seq) = Snowflake::parts(sf);
21 println!(
22 "Snowflake: {sf} (ts+epoch={}, worker={worker}, seq={seq})",
23 ts_offset + gen.epoch_ms()
24 );
25
26 println!("NanoID 21: {}", nanoid::generate());
27 println!("NanoID 8: {}", nanoid::with_length(8));
28
29 assert_eq!(v4, Uuid::parse_str(&v4.to_string()).unwrap());
30 assert_eq!(a, Ulid::parse_str(&a.to_string()).unwrap());
31}More examples
13fn main() {
14 println!("== Single-millisecond burst ==");
15
16 // 1000 ULIDs back-to-back. Most will share the same ms prefix;
17 // the monotonic factory guarantees b > a for every consecutive pair.
18 let mut ids: Vec<Ulid> = (0..1000).map(|_| Ulid::new()).collect();
19
20 let same_ms = ids
21 .windows(2)
22 .filter(|w| w[0].timestamp_ms() == w[1].timestamp_ms())
23 .count();
24 println!("count = {}", ids.len());
25 println!("same-ms pairs = {same_ms} of {}", ids.len() - 1);
26
27 let strictly_increasing = ids.windows(2).all(|w| w[1] > w[0]);
28 println!("monotonic = {strictly_increasing}");
29
30 let unique: HashSet<&Ulid> = ids.iter().collect();
31 println!("unique = {} of {}", unique.len(), ids.len());
32
33 println!("\n== First and last of the burst ==");
34 let first = ids.first().unwrap();
35 let last = ids.last().unwrap();
36 println!("first = {first}");
37 println!("last = {last}");
38 println!("ts_first = {} ms", first.timestamp_ms());
39 println!("ts_last = {} ms", last.timestamp_ms());
40
41 println!("\n== Crockford base32 round-trip ==");
42 let sample = Ulid::new();
43 let s = sample.to_string();
44 let parsed = Ulid::parse_str(&s).unwrap();
45 println!("sample = {sample}");
46 println!("parsed = {parsed}");
47 println!("equal = {}", sample == parsed);
48
49 println!("\n== Substitutions accepted by parse_str ==");
50 let with_subs = Ulid::parse_str("0IIIIIIIIIIIIIIIIIIIIIIIII").unwrap();
51 let canonical = Ulid::parse_str("01111111111111111111111111").unwrap();
52 println!("\"0III...\" == \"0111...\" = {}", with_subs == canonical);
53
54 println!("\n== Sorting by Display is sorting by time ==");
55 ids.sort_by_key(|u| u.to_string());
56 let same = ids.windows(2).all(|w| w[1] >= w[0]);
57 println!("string sort = byte sort = {same}");
58}Sourcepub const fn from_bytes(bytes: &[u8; 16]) -> Self
pub const fn from_bytes(bytes: &[u8; 16]) -> Self
Wrap a 16-byte big-endian representation as-is.
§Example
use id_forge::ulid::Ulid;
let id = Ulid::new();
let copy = Ulid::from_bytes(id.as_bytes());
assert_eq!(id, copy);Sourcepub const fn as_bytes(&self) -> &[u8; 16]
pub const fn as_bytes(&self) -> &[u8; 16]
Return the raw 16-byte big-endian representation.
§Example
use id_forge::ulid::Ulid;
assert_eq!(Ulid::nil().as_bytes(), &[0u8; 16]);Sourcepub const fn timestamp_ms(&self) -> u64
pub const fn timestamp_ms(&self) -> u64
Return the 48-bit millisecond timestamp prefix.
§Example
use id_forge::ulid::Ulid;
let id = Ulid::new();
assert!(id.timestamp_ms() > 0);Examples found in repository?
13fn main() {
14 println!("== Single-millisecond burst ==");
15
16 // 1000 ULIDs back-to-back. Most will share the same ms prefix;
17 // the monotonic factory guarantees b > a for every consecutive pair.
18 let mut ids: Vec<Ulid> = (0..1000).map(|_| Ulid::new()).collect();
19
20 let same_ms = ids
21 .windows(2)
22 .filter(|w| w[0].timestamp_ms() == w[1].timestamp_ms())
23 .count();
24 println!("count = {}", ids.len());
25 println!("same-ms pairs = {same_ms} of {}", ids.len() - 1);
26
27 let strictly_increasing = ids.windows(2).all(|w| w[1] > w[0]);
28 println!("monotonic = {strictly_increasing}");
29
30 let unique: HashSet<&Ulid> = ids.iter().collect();
31 println!("unique = {} of {}", unique.len(), ids.len());
32
33 println!("\n== First and last of the burst ==");
34 let first = ids.first().unwrap();
35 let last = ids.last().unwrap();
36 println!("first = {first}");
37 println!("last = {last}");
38 println!("ts_first = {} ms", first.timestamp_ms());
39 println!("ts_last = {} ms", last.timestamp_ms());
40
41 println!("\n== Crockford base32 round-trip ==");
42 let sample = Ulid::new();
43 let s = sample.to_string();
44 let parsed = Ulid::parse_str(&s).unwrap();
45 println!("sample = {sample}");
46 println!("parsed = {parsed}");
47 println!("equal = {}", sample == parsed);
48
49 println!("\n== Substitutions accepted by parse_str ==");
50 let with_subs = Ulid::parse_str("0IIIIIIIIIIIIIIIIIIIIIIIII").unwrap();
51 let canonical = Ulid::parse_str("01111111111111111111111111").unwrap();
52 println!("\"0III...\" == \"0111...\" = {}", with_subs == canonical);
53
54 println!("\n== Sorting by Display is sorting by time ==");
55 ids.sort_by_key(|u| u.to_string());
56 let same = ids.windows(2).all(|w| w[1] >= w[0]);
57 println!("string sort = byte sort = {same}");
58}Sourcepub fn parse_str(input: &str) -> Result<Self, ParseError>
pub fn parse_str(input: &str) -> Result<Self, ParseError>
Parse a 26-character Crockford base32 ULID, case-insensitive.
Accepts the substitution rules from the spec: I, L decode
to 1; O decodes to 0. U is reserved and rejected.
Returns ParseError on length, character, or leading-bits
violations.
§Example
use id_forge::ulid::Ulid;
let id = Ulid::parse_str("01ARZ3NDEKTSV4RRFFQ69G5FAV").unwrap();
assert_eq!(id.to_string(), "01ARZ3NDEKTSV4RRFFQ69G5FAV");Examples found in repository?
7fn main() {
8 let v4 = Uuid::v4();
9 println!("UUID v4: {v4} (version={})", v4.version());
10 println!("UUID v7: {}", Uuid::v7());
11 println!("UUID nil: {}", Uuid::nil());
12
13 let a = Ulid::new();
14 let b = Ulid::new();
15 println!("ULID a: {a}");
16 println!("ULID b: {b} (monotonic: {})", b > a);
17
18 let gen = Snowflake::new(1);
19 let sf = gen.next_id();
20 let (ts_offset, worker, seq) = Snowflake::parts(sf);
21 println!(
22 "Snowflake: {sf} (ts+epoch={}, worker={worker}, seq={seq})",
23 ts_offset + gen.epoch_ms()
24 );
25
26 println!("NanoID 21: {}", nanoid::generate());
27 println!("NanoID 8: {}", nanoid::with_length(8));
28
29 assert_eq!(v4, Uuid::parse_str(&v4.to_string()).unwrap());
30 assert_eq!(a, Ulid::parse_str(&a.to_string()).unwrap());
31}More examples
13fn main() {
14 println!("== Single-millisecond burst ==");
15
16 // 1000 ULIDs back-to-back. Most will share the same ms prefix;
17 // the monotonic factory guarantees b > a for every consecutive pair.
18 let mut ids: Vec<Ulid> = (0..1000).map(|_| Ulid::new()).collect();
19
20 let same_ms = ids
21 .windows(2)
22 .filter(|w| w[0].timestamp_ms() == w[1].timestamp_ms())
23 .count();
24 println!("count = {}", ids.len());
25 println!("same-ms pairs = {same_ms} of {}", ids.len() - 1);
26
27 let strictly_increasing = ids.windows(2).all(|w| w[1] > w[0]);
28 println!("monotonic = {strictly_increasing}");
29
30 let unique: HashSet<&Ulid> = ids.iter().collect();
31 println!("unique = {} of {}", unique.len(), ids.len());
32
33 println!("\n== First and last of the burst ==");
34 let first = ids.first().unwrap();
35 let last = ids.last().unwrap();
36 println!("first = {first}");
37 println!("last = {last}");
38 println!("ts_first = {} ms", first.timestamp_ms());
39 println!("ts_last = {} ms", last.timestamp_ms());
40
41 println!("\n== Crockford base32 round-trip ==");
42 let sample = Ulid::new();
43 let s = sample.to_string();
44 let parsed = Ulid::parse_str(&s).unwrap();
45 println!("sample = {sample}");
46 println!("parsed = {parsed}");
47 println!("equal = {}", sample == parsed);
48
49 println!("\n== Substitutions accepted by parse_str ==");
50 let with_subs = Ulid::parse_str("0IIIIIIIIIIIIIIIIIIIIIIIII").unwrap();
51 let canonical = Ulid::parse_str("01111111111111111111111111").unwrap();
52 println!("\"0III...\" == \"0111...\" = {}", with_subs == canonical);
53
54 println!("\n== Sorting by Display is sorting by time ==");
55 ids.sort_by_key(|u| u.to_string());
56 let same = ids.windows(2).all(|w| w[1] >= w[0]);
57 println!("string sort = byte sort = {same}");
58}