diff --git a/examples/demo.rs b/examples/demo.rs index f493ff3..34f5b35 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -14,13 +14,16 @@ fn main() -> std::io::Result<()> { println!("offset : {}", rng.gen_range_i32_in(-10..=10)?); 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}"); - let hex = rng.string_from(charset::HEX_LOWER, 32)?; + let hex = rng.hex(32)?; 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}"); Ok(()) diff --git a/examples/presets.rs b/examples/presets.rs new file mode 100644 index 0000000..92b6f5e --- /dev/null +++ b/examples/presets.rs @@ -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(()) +} diff --git a/src/lib.rs b/src/lib.rs index 8bbad4c..6c716a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ //! - Range helpers sample integer spans. //! - Slice helpers choose caller-owned values by reference. //! - [`charset`] contains reusable ASCII alphabets for string generation. +//! - String helpers compose those alphabets into common token formats. use std::{ fs::File, @@ -500,6 +501,75 @@ impl OsRandom { } 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 { + 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 { + 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 { + self.string_from(charset::DIGITS, len) + } } /// Forwards reads directly to the underlying `/dev/urandom` handle so an