diff --git a/Cargo.toml b/Cargo.toml index 758f9f5..a4c4ef0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rng" -version = "0.1.0" +version = "0.2.0" authors = ["Avril "] edition = "2018" diff --git a/src/main.rs b/src/main.rs index ad80b07..90a3f56 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate getrandom; use getrandom::*; +mod parse; mod r#impl; fn get() -> Result @@ -45,6 +46,7 @@ fn usage() println!("Usage: rng --ceil []"); println!("Usage: rng --of "); println!("Usage: rng --shuffle "); + println!("Usage: rng --bytes [k|m|g]"); } fn range(args: &[String]) -> Result<(), Error> @@ -146,6 +148,29 @@ fn shuffle(args: &[String]) -> Result<(), Error> Ok(()) } +fn bytes(args: &[String]) -> Result<(), Error> +{ + if args.len() < 1 { + usage(); + } else { + let num = parse::bytes(&args[0]).expect("Failed to parse number of bytes") as usize; + let mut mem = Vec::with_capacity(num); + + debug_assert_eq!(mem.capacity(), num); + // SAFETY: populating uninitialised memory with random data. There are no reads to the uninitialised data. + unsafe { + mem.set_len(num); + populate(&mut mem[..])?; + } + debug_assert_eq!(num, mem.len()); + + let stdout = std::io::stdout(); + use std::io::Write; + stdout.lock().write_all(&mem[..]).expect("write error"); + } + Ok(()) +} + fn main() -> Result<(), Error> { let args: Vec = std::env::args().collect(); @@ -161,6 +186,7 @@ fn main() -> Result<(), Error> { "--floor" => floor(&args[2..])?, "--of" => of(&args[2..])?, "--shuffle" => shuffle(&args[2..])?, + "--bytes" => bytes(&args[2..])?, _ => usage() }; Ok(()) diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..d59bbea --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,35 @@ +use std::{ + fmt, error, +}; +#[derive(Debug)] +pub struct ReadBytesError(String); + +impl error::Error for ReadBytesError{} +impl fmt::Display for ReadBytesError +{ + #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "{:?} is not a valid integer of bytes", self.0) + } +} + +/// Parse bytes from a string +pub fn bytes(string: impl AsRef) -> Result +{ + let string = string.as_ref(); + let string = string.trim(); + + let last = string.chars().last().ok_or_else(move || ReadBytesError(string.to_owned()))?; + + let (sl, mul) = match last { + 'k' | 'K' => (1, 1024), + 'm' | 'M' => (1, 1024 * 1024), + 'g' | 'G' => (1, 1024 * 1024 * 1024), + _ if last.is_numeric() => (0, 1), + _ => return Err(ReadBytesError(string.to_owned())), + }; + string[..(string.len()-sl)].parse() + .map(|x: u64| x * mul) + .map_err(move |_| ReadBytesError(string.to_owned())) +} +