Skip to main content

nanoid_validate/
nanoid_validate.rs

1//! NanoID alphabet validation.
2//!
3//! Demonstrates:
4//!   * `nanoid::try_custom` — strict entry point that rejects empty
5//!     and duplicate-byte alphabets
6//!   * `nanoid::validate_alphabet` — call once at startup to vet a
7//!     configuration value before the hot path
8//!   * The difference between the permissive `custom` and the
9//!     strict `try_custom`
10//!
11//! Run with: `cargo run --release --example nanoid_validate`
12
13use id_forge::nanoid::{self, AlphabetError};
14
15fn main() {
16    println!("== try_custom: happy path ==");
17    let id = nanoid::try_custom(16, b"0123456789abcdef").unwrap();
18    println!("  {id}");
19
20    println!("\n== try_custom: empty alphabet ==");
21    match nanoid::try_custom(8, b"") {
22        Ok(s) => println!("  unexpected ok: {s}"),
23        Err(e) => println!("  Err: {e}"),
24    }
25
26    println!("\n== try_custom: duplicate byte ==");
27    match nanoid::try_custom(8, b"abcda") {
28        Ok(s) => println!("  unexpected ok: {s}"),
29        Err(AlphabetError::Duplicate(b)) => {
30            println!("  Err: duplicate byte 0x{b:02x} ({:?})", b as char);
31        }
32        Err(e) => println!("  Err: {e}"),
33    }
34
35    println!("\n== validate_alphabet for startup-time config check ==");
36    let alphabets: &[(&str, &[u8])] = &[
37        (
38            "url-safe-64",
39            b"_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
40        ),
41        ("hex", b"0123456789abcdef"),
42        ("empty", b""),
43        ("dup", b"aab"),
44    ];
45    for (label, alphabet) in alphabets {
46        match nanoid::validate_alphabet(alphabet) {
47            Ok(()) => println!("  {label:<14} OK ({} chars)", alphabet.len()),
48            Err(e) => println!("  {label:<14} REJECTED: {e}"),
49        }
50    }
51
52    println!("\n== Permissive `custom` tolerates duplicates ==");
53    // Duplicates skew the output toward repeated chars. `custom`
54    // accepts this by design; `try_custom` does not.
55    let skewed = nanoid::custom(20, b"AAAAAA");
56    println!("  custom(20, b\"AAAAAA\") = {skewed}");
57
58    println!("\n== Cache a validated alphabet once at startup ==");
59    let alphabet = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ";
60    nanoid::validate_alphabet(alphabet).expect("startup: config alphabet must be valid");
61    // ... hot path now uses `custom` since the alphabet has already
62    // been vetted; no per-call validation cost.
63    for _ in 0..3 {
64        println!("  {}", nanoid::custom(12, alphabet));
65    }
66}