Generate a fresh lowercased ULID-style stem: a 48-bit millisecond timestamp followed by 80 bits of randomness, encoded in Crockford base32 (26 chars), lowercased. No ULID crate is a workspace dependency, so this is a self-contained generator using the existing `chrono` + `uuid` deps — deliberately NOT a `PREFIX-N` scheme (memories have no prefix allocator).
()
| 138 | /// self-contained generator using the existing `chrono` + `uuid` deps — |
| 139 | /// deliberately NOT a `PREFIX-N` scheme (memories have no prefix allocator). |
| 140 | fn generate_ulid_lowercased() -> String { |
| 141 | const CROCKFORD: &[u8; 32] = b"0123456789abcdefghjkmnpqrstvwxyz"; |
| 142 | |
| 143 | let now_ms = chrono::Utc::now().timestamp_millis().max(0) as u128; |
| 144 | // 80 bits of randomness from a v4 UUID. |
| 145 | let rand = uuid::Uuid::new_v4().as_u128(); |
| 146 | |
| 147 | // A ULID is a 128-bit value: 48-bit time (high) + 80-bit randomness (low). |
| 148 | let value: u128 = (now_ms << 80) | (rand & ((1u128 << 80) - 1)); |
| 149 | |
| 150 | // Encode the 128-bit value as 26 Crockford base32 chars (130 bits, so the |
| 151 | // top 2 bits of the first symbol are always 0 — standard ULID layout). |
| 152 | let mut out = [0u8; 26]; |
| 153 | let mut v = value; |
| 154 | for slot in out.iter_mut().rev() { |
| 155 | *slot = CROCKFORD[(v & 0x1f) as usize]; |
| 156 | v >>= 5; |
| 157 | } |
| 158 | String::from_utf8(out.to_vec()).expect("crockford alphabet is valid ASCII") |
| 159 | } |
| 160 | |
| 161 | #[cfg(test)] |
| 162 | mod tests { |