diff --git a/README.md b/README.md index aa89ab3..6ab7018 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,3 @@ # badargs -A Rust fully type-safe argument parser without proc-macros -Usability comes after that - -oh and it's also not even close to being usable in any way at all so there's that - -oh and also 0 dependencies btw \ No newline at end of file +A zero-dependency full type-safe argument parser. diff --git a/src/lib.rs b/src/lib.rs index 40121a7..d29671d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,9 +55,9 @@ pub fn badargs() -> BadArgs where S: IntoSchema, { - let arg_schema = Schema::create::().expect("Invalid schema!"); + let arg_schema = Schema::create::().expect("Invalid schema"); - let args = CliArgs::from_args(&arg_schema, std::env::args()); + let args = CliArgs::from_args(&arg_schema, std::env::args_os()); match args { Ok(args) => BadArgs { args }, Err(err) => reporting::report(err), @@ -132,6 +132,7 @@ mod sealed { mod error { use crate::schema::SchemaKind; + use std::ffi::OsString; /// Invalid schema #[derive(Debug, Clone, Eq, PartialEq)] @@ -149,5 +150,6 @@ mod error { INan(String), UNan(String), CombinedShortWithValue(String), + InvalidUtf8(OsString), } } diff --git a/src/parse.rs b/src/parse.rs index 405373c..cc513b5 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -2,6 +2,7 @@ use crate::error::CallError; use crate::schema::{Schema, SchemaKind}; use std::any::Any; use std::collections::HashMap; +use std::ffi::OsString; type Result = std::result::Result; @@ -12,10 +13,14 @@ pub(crate) struct CliArgs { } impl CliArgs { - pub fn from_args(schema: &Schema, mut args: impl Iterator) -> Result { + pub fn from_args(schema: &Schema, mut args: impl Iterator) -> Result { let mut result = Self::default(); while let Some(arg) = args.next() { + let arg = arg + .into_string() + .map_err(|os_str| CallError::InvalidUtf8(os_str))?; + if let Some(long) = arg.strip_prefix("--") { parse_long(schema, &mut result, long, &mut args)?; } else if let Some(shorts) = arg.strip_prefix('-') { @@ -47,7 +52,7 @@ fn parse_shorts( schema: &Schema, results: &mut CliArgs, shorts: &str, - args: &mut impl Iterator, + args: &mut impl Iterator, ) -> Result<()> { // there are kinds of short arguments // single shorts that takes values: `-o main` @@ -88,7 +93,7 @@ fn parse_long( schema: &Schema, results: &mut CliArgs, long: &str, - args: &mut impl Iterator, + args: &mut impl Iterator, ) -> Result<()> { let command = schema .long(long) @@ -101,19 +106,23 @@ fn parse_value( kind: SchemaKind, results: &mut CliArgs, long: &'static str, - args: &mut impl Iterator, + args: &mut impl Iterator, ) -> Result<()> { match kind { SchemaKind::String => { let string = args .next() - .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))?; + .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))? + .into_string() + .map_err(|os_str| CallError::InvalidUtf8(os_str))?; results.insert(long, Box::new(string)); } SchemaKind::INum => { let integer = args .next() .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))? + .into_string() + .map_err(|os_str| CallError::InvalidUtf8(os_str))? .parse::() .map_err(|_| CallError::INan(long.to_string()))?; results.insert(long, Box::new(integer)) @@ -122,6 +131,8 @@ fn parse_value( let integer = args .next() .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))? + .into_string() + .map_err(|os_str| CallError::InvalidUtf8(os_str))? .parse::() .map_err(|_| CallError::UNan(long.to_string()))?; results.insert(long, Box::new(integer)) @@ -158,7 +169,11 @@ mod test { } fn parse_args(args: &str) -> Result { - CliArgs::from_args(&schema(), args.split_whitespace().map(|s| s.to_owned())) + CliArgs::from_args( + &schema(), + args.split_whitespace() + .map(|s| OsString::from(s.to_owned())), + ) } #[test] diff --git a/src/reporting.rs b/src/reporting.rs index 30425f8..44b5d8c 100644 --- a/src/reporting.rs +++ b/src/reporting.rs @@ -19,7 +19,8 @@ pub fn report(err: CallError) -> ! { } CallError::INan(arg) => println!("error: argument '{}' expected a positive integer value, but got an invalid positive integer.", arg), CallError::UNan(arg) => println!("error: argument '{}' expected an integer value, but got an invalid integer.", arg), - CallError::CombinedShortWithValue(arg) => println!("error: using argument expecting value '{}' in position where only flags are allowed", arg) + CallError::CombinedShortWithValue(arg) => println!("error: using argument expecting value '{}' in position where only flags are allowed", arg), + CallError::InvalidUtf8(os_str) => println!("error: invalid utf8: '{}'", os_str.to_string_lossy()), } std::process::exit(1)