feat: add common string presets
Add token, hex, and pin helpers for the common ASCII string formats already represented by the crate's built-in charsets. These methods keep frequent use cases concise while continuing to route through string_from, so callers still get the same uniform per-character sampling behavior. Avoid adding a password preset in this change. Password generation implies policy choices around symbols, ambiguous characters, and service-specific constraints, while these presets are direct names for existing alphabets. Document every preset with doctested examples and add a runnable presets example. Update the demo to show both presets and custom string generation. Test Plan: - cargo test - cargo clippy - cargo clippy --benches - cargo clippy --tests - cargo +nightly fmt Refs: IDEAS.md ergonomics backlog
This commit is contained in:
+6
-3
@@ -14,13 +14,16 @@ fn main() -> std::io::Result<()> {
|
|||||||
println!("offset : {}", rng.gen_range_i32_in(-10..=10)?);
|
println!("offset : {}", rng.gen_range_i32_in(-10..=10)?);
|
||||||
println!("index : {}", rng.gen_range_usize_in(0..16)?);
|
println!("index : {}", rng.gen_range_usize_in(0..16)?);
|
||||||
|
|
||||||
let token = rng.string_from(charset::ALPHANUMERIC, 24)?;
|
let token = rng.token(24)?;
|
||||||
println!("token : {token}");
|
println!("token : {token}");
|
||||||
|
|
||||||
let hex = rng.string_from(charset::HEX_LOWER, 32)?;
|
let hex = rng.hex(32)?;
|
||||||
println!("hex : {hex}");
|
println!("hex : {hex}");
|
||||||
|
|
||||||
let pin = rng.string_from(charset::DIGITS, 6)?;
|
let custom = rng.string_from(charset::ALPHANUMERIC, 12)?;
|
||||||
|
println!("custom : {custom}");
|
||||||
|
|
||||||
|
let pin = rng.pin(6)?;
|
||||||
println!("pin : {pin}");
|
println!("pin : {pin}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//! Run with: `cargo run --example presets`
|
||||||
|
|
||||||
|
use ez_urandom::OsRandom;
|
||||||
|
|
||||||
|
fn main() -> std::io::Result<()> {
|
||||||
|
let mut rng = OsRandom::try_new()?;
|
||||||
|
|
||||||
|
let token = rng.token(24)?;
|
||||||
|
let hex = rng.hex(32)?;
|
||||||
|
let pin = rng.pin(6)?;
|
||||||
|
|
||||||
|
println!("token: {token}");
|
||||||
|
println!("hex : {hex}");
|
||||||
|
println!("pin : {pin}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
+70
@@ -16,6 +16,7 @@
|
|||||||
//! - Range helpers sample integer spans.
|
//! - Range helpers sample integer spans.
|
||||||
//! - Slice helpers choose caller-owned values by reference.
|
//! - Slice helpers choose caller-owned values by reference.
|
||||||
//! - [`charset`] contains reusable ASCII alphabets for string generation.
|
//! - [`charset`] contains reusable ASCII alphabets for string generation.
|
||||||
|
//! - String helpers compose those alphabets into common token formats.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
@@ -500,6 +501,75 @@ impl OsRandom {
|
|||||||
}
|
}
|
||||||
Ok(String::from_utf8(buf).expect("ASCII bytes are valid UTF-8"))
|
Ok(String::from_utf8(buf).expect("ASCII bytes are valid UTF-8"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an alphanumeric ASCII token of `len` characters.
|
||||||
|
///
|
||||||
|
/// Characters are drawn uniformly from [`charset::ALPHANUMERIC`].
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns any I/O error produced while reading from `/dev/urandom`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> std::io::Result<()> {
|
||||||
|
/// let mut rng = ez_urandom::OsRandom::try_new()?;
|
||||||
|
/// let token = rng.token(32)?;
|
||||||
|
/// assert_eq!(token.len(), 32);
|
||||||
|
/// assert!(token.bytes().all(|byte| byte.is_ascii_alphanumeric()));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn token(&mut self, len: usize) -> io::Result<String> {
|
||||||
|
self.string_from(charset::ALPHANUMERIC, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a lowercase hexadecimal string of `len` characters.
|
||||||
|
///
|
||||||
|
/// Characters are drawn uniformly from [`charset::HEX_LOWER`]. The `len`
|
||||||
|
/// argument is the number of hex characters, not the number of source
|
||||||
|
/// bytes.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns any I/O error produced while reading from `/dev/urandom`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> std::io::Result<()> {
|
||||||
|
/// let mut rng = ez_urandom::OsRandom::try_new()?;
|
||||||
|
/// let hex = rng.hex(16)?;
|
||||||
|
/// assert_eq!(hex.len(), 16);
|
||||||
|
/// assert!(hex.bytes().all(|byte| byte.is_ascii_hexdigit()));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn hex(&mut self, len: usize) -> io::Result<String> {
|
||||||
|
self.string_from(charset::HEX_LOWER, len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a decimal digit string of `len` characters.
|
||||||
|
///
|
||||||
|
/// This is useful for PINs, short human-entered codes, and other cases
|
||||||
|
/// where only ASCII digits are accepted.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns any I/O error produced while reading from `/dev/urandom`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> std::io::Result<()> {
|
||||||
|
/// let mut rng = ez_urandom::OsRandom::try_new()?;
|
||||||
|
/// let pin = rng.pin(6)?;
|
||||||
|
/// assert_eq!(pin.len(), 6);
|
||||||
|
/// assert!(pin.bytes().all(|byte| byte.is_ascii_digit()));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn pin(&mut self, len: usize) -> io::Result<String> {
|
||||||
|
self.string_from(charset::DIGITS, len)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forwards reads directly to the underlying `/dev/urandom` handle so an
|
/// Forwards reads directly to the underlying `/dev/urandom` handle so an
|
||||||
|
|||||||
Reference in New Issue
Block a user