Skip to main content

custom

Function custom 

Source
pub fn custom(length: usize, alphabet: &[u8]) -> String
Available on crate feature nanoid only.
Expand description

Generate a NanoID with a custom length and alphabet.

This entry point is permissive: an empty alphabet returns the empty string, and duplicate bytes in the alphabet are tolerated (the repeated characters appear with higher probability). Use try_custom when you want validation to surface those cases as an error.

ยงExample

use id_forge::nanoid;

let id = nanoid::custom(8, b"0123456789ABCDEF");
assert_eq!(id.len(), 8);
assert!(id.chars().all(|c| "0123456789ABCDEF".contains(c)));
Examples found in repository?
examples/bench.rs (line 50)
33fn main() {
34    println!("id-forge throughput (single thread, release build)");
35    println!("---------------------------------------------------");
36
37    let iters = 1_000_000;
38    bench("Uuid::v4", iters, Uuid::v4);
39    bench("Uuid::v7", iters, Uuid::v7);
40    bench("Ulid::new", iters, Ulid::new);
41
42    let sf = Snowflake::new(1);
43    bench("Snowflake::next_id", iters, || sf.next_id());
44
45    bench("nanoid::generate", iters / 5, nanoid::generate);
46    bench("nanoid::with_length(8)", iters / 5, || {
47        nanoid::with_length(8)
48    });
49    bench("nanoid::custom(16, hex)", iters / 5, || {
50        nanoid::custom(16, b"0123456789abcdef")
51    });
52    bench("nanoid::custom(21, 17-char)", iters / 5, || {
53        nanoid::custom(21, b"ABCDEFGHIJKLMNOPQ")
54    });
55}
More examples
Hide additional examples
examples/nanoid_short_url.rs (line 35)
21fn main() {
22    println!("== Default 21-char URL-safe IDs ==");
23    for _ in 0..5 {
24        println!("  {}", nanoid::generate());
25    }
26
27    println!("\n== Short codes (8 chars, URL-safe default) ==");
28    for _ in 0..5 {
29        println!("  {}", nanoid::with_length(8));
30    }
31
32    println!("\n== Readable alphabet (no 0/O/I/L/U), 10 chars ==");
33    println!("  alphabet has {} chars", READABLE_32.len());
34    for _ in 0..5 {
35        println!("  {}", nanoid::custom(10, READABLE_32));
36    }
37
38    println!("\n== URL-safe lowercase, 12 chars ==");
39    for _ in 0..5 {
40        println!("  {}", nanoid::custom(12, URL_36));
41    }
42
43    println!("\n== Collision sweep at length 8 on URL_36 ==");
44    let n = 100_000;
45    let mut seen = HashSet::with_capacity(n);
46    let mut collisions = 0usize;
47    for _ in 0..n {
48        if !seen.insert(nanoid::custom(8, URL_36)) {
49            collisions += 1;
50        }
51    }
52    println!("  drew {n} IDs of length 8");
53    println!("  collisions = {collisions}");
54    println!("  (URL_36^8 = {} ids/space)", (URL_36.len() as u64).pow(8));
55}
examples/nanoid_validate.rs (line 55)
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}