bento-kit 0.1.1

A bento box of common Rust utilities: id generation, timing, masking
Documentation
//! Nanoid wrappers (URL-safe short IDs).

/// Default nanoid length (matches the upstream library's default).
pub const DEFAULT_NANOID_LEN: usize = 21;

/// Generate a nanoid of the default length (21 chars).
///
/// Uses the URL-safe alphabet `A-Za-z0-9_-`.
pub fn nanoid() -> String {
    nanoid::nanoid!()
}

/// Generate a nanoid of a custom length using the URL-safe alphabet.
pub fn nanoid_with_len(len: usize) -> String {
    nanoid::nanoid!(len)
}

/// Generate a nanoid of a custom length and alphabet.
///
/// ```
/// let id = bento_kit::id::nanoid_with_alphabet(10, &['a','b','c']);
/// assert_eq!(id.len(), 10);
/// assert!(id.chars().all(|c| matches!(c, 'a' | 'b' | 'c')));
/// ```
pub fn nanoid_with_alphabet(len: usize, alphabet: &[char]) -> String {
    nanoid::nanoid!(len, alphabet)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn default_length() {
        let id = nanoid();
        assert_eq!(id.len(), DEFAULT_NANOID_LEN);
    }

    #[test]
    fn custom_length() {
        for len in [4_usize, 10, 32, 64] {
            assert_eq!(nanoid_with_len(len).len(), len);
        }
    }

    #[test]
    fn url_safe_alphabet_by_default() {
        let id = nanoid_with_len(64);
        assert!(
            id.chars()
                .all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-'),
            "unexpected chars in {id}"
        );
    }

    #[test]
    fn custom_alphabet_respects_alphabet() {
        let alphabet = ['x', 'y', 'z'];
        let id = nanoid_with_alphabet(50, &alphabet);
        assert_eq!(id.len(), 50);
        assert!(id.chars().all(|c| alphabet.contains(&c)));
    }
}