1use base64::Engine as _;
4use base64::engine::general_purpose::URL_SAFE_NO_PAD;
5use sha2::{Digest, Sha256};
6use std::fmt::Write as _;
7
8const ID_BYTES: usize = 32;
10const ID_LEN: usize = 43;
12
13pub(crate) fn generate() -> Result<String, getrandom::Error> {
15 let mut bytes = [0u8; ID_BYTES];
16 getrandom::fill(&mut bytes)?;
17 Ok(URL_SAFE_NO_PAD.encode(bytes))
18}
19
20pub(crate) fn well_formed(id: &str) -> bool {
23 id.len() == ID_LEN
24 && id
25 .bytes()
26 .all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_')
27}
28
29#[must_use]
32pub fn id_hash(id: &str) -> String {
33 let digest = Sha256::digest(id.as_bytes());
34 let mut out = String::with_capacity(digest.len() * 2);
35 for byte in digest {
36 let _ = write!(out, "{byte:02x}");
38 }
39 out
40}