diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..c70041e --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,85 @@ +use crate::commands::CommandMap; +use bnum::types::U512; + +pub fn run(args: &[String]) -> Result { + let input = ParsedInput::try_from(args)?; + let cmd_map = CommandMap::default(); + match cmd_map.get(&input.command_name) { + Some(cmd) => Ok(format!("{}\n{}", input, cmd.run(&input.number))), + None => Err(Error::CommandNotFound(cmd_map.available_commands())), + } +} + +struct ParsedInput { + number: U512, + digit_len: usize, + command_name: String, +} + +impl TryFrom<&[String]> for ParsedInput { + type Error = Error; + + fn try_from(value: &[String]) -> Result { + let slice: &[String; 3] = value.try_into().map_err(|_| Error::IncorrectNumArgs)?; + Ok(ParsedInput { + number: slice[2].parse().map_err(|_| Error::ParseIntErr)?, + digit_len: slice[2].len(), + command_name: slice[1].to_string(), + }) + } +} + +impl std::fmt::Display for ParsedInput { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Using command {} with number {} ({} digits)", + self.command_name, self.number, self.digit_len + ) + } +} + +#[derive(PartialEq, Debug)] +pub enum Error { + CommandNotFound(String), + ParseIntErr, + IncorrectNumArgs, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn happy_cases() { + let cmap = CommandMap::default(); + for command in cmap.available_commands().split(", ") { + assert!(run(&[ + String::from("rustic_factors"), + String::from(command), + String::from("123") + ]) + .is_ok()); + } + } + + #[test] + fn unsupported_command() { + match run(&[ + String::from("rustic_factors"), + String::from("unsupported command"), + String::from("123"), + ]) { + Err(Error::CommandNotFound(_)) => (), + _ => panic!(), + } + } + + #[test] + fn too_few_args() { + assert_eq!( + run(&[String::from("rustic_factors")]).unwrap_err(), + Error::IncorrectNumArgs, + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 2172799..f347aad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod algorithms; +pub mod cli; pub mod commands; pub mod factorization; pub mod orchestration; diff --git a/src/main.rs b/src/main.rs index ce5d347..e891fae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,98 +1,14 @@ -use bnum::types::U512; -use rustic_factors::commands::CommandMap; +use rustic_factors::cli; use std::env; fn main() { let args: Vec = env::args().collect(); - match cli(&args) { + match cli::run(&args) { Ok(result) => println!("{result}"), - Err(CliErr::ParseIntErr) => eprintln!("Please provide a number in range [0, 2⁵¹²)"), - Err(CliErr::IncorrectNumArgs) => eprintln!("Usage: {} ", args[0]), - Err(CliErr::CommandNotFound(commands)) => { + Err(cli::Error::ParseIntErr) => eprintln!("Please provide a number in range [0, 2⁵¹²)"), + Err(cli::Error::IncorrectNumArgs) => eprintln!("Usage: {} ", args[0]), + Err(cli::Error::CommandNotFound(commands)) => { eprintln!("Unknown command. Available options: {commands}.") } } } - -fn cli(args: &[String]) -> Result { - let input = ParsedInput::try_from(args)?; - let cmd_map = CommandMap::default(); - match cmd_map.get(&input.command_name) { - Some(cmd) => Ok(format!("{}\n{}", input, cmd.run(&input.number))), - None => Err(CliErr::CommandNotFound(cmd_map.available_commands())), - } -} - -struct ParsedInput { - number: U512, - digit_len: usize, - command_name: String, -} - -impl TryFrom<&[String]> for ParsedInput { - type Error = CliErr; - - fn try_from(value: &[String]) -> Result { - let slice: &[String; 3] = value.try_into().map_err(|_| CliErr::IncorrectNumArgs)?; - Ok(ParsedInput { - number: slice[2].parse().map_err(|_| CliErr::ParseIntErr)?, - digit_len: slice[2].len(), - command_name: slice[1].to_string(), - }) - } -} - -impl std::fmt::Display for ParsedInput { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Using command {} with number {} ({} digits)", - self.command_name, self.number, self.digit_len - ) - } -} - -#[derive(PartialEq, Debug)] -enum CliErr { - CommandNotFound(String), - ParseIntErr, - IncorrectNumArgs, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn happy_cases() { - let cmap = CommandMap::default(); - for command in cmap.available_commands().split(", ") { - assert!(cli(&[ - String::from("rustic_factors"), - String::from(command), - String::from("123") - ]) - .is_ok()); - } - } - - #[test] - fn unsupported_command() { - match cli(&[ - String::from("rustic_factors"), - String::from("unsupported command"), - String::from("123"), - ]) { - Err(CliErr::CommandNotFound(_)) => (), - _ => panic!(), - } - } - - #[test] - fn too_few_args() { - assert_eq!( - cli(&[String::from("rustic_factors")]).unwrap_err(), - CliErr::IncorrectNumArgs, - ); - } -}