#![allow(dead_code, warnings)] use std::path::PathBuf; use clap::Parser; // PositionalArgs has logical names, from an awkwardly ordered syntax of `seq` // seq [OPTION] [FIRST [INCREMENT]] LAST #[derive(Debug, Default)] struct PositionalArgs<'A> { start: Option<&'A str>, increment: Option<&'A str>, end: &'A str } use std::ffi::OsStr; use std::fmt::Debug; macro_rules! parse_u64 { ($var:ident) => { Some( $var .as_ref() .parse::() .expect( &format!("Could not parse '{:?}'", stringify!($var)) ) ) }; } use std::convert::TryFrom; impl<'A, T> TryFrom<&'A [T]> for PositionalArgs<'A> where T: 'A + std::fmt::Display + Debug + AsRef { type Error = &'static str; fn try_from(mut vec: &'A [T]) -> Result { // println!("ARGUMENT: {:?}", vec); if vec.len() > 3 { panic!("Too many positional arguments") } let o = match (vec.get(0), vec.get(1), vec.get(2)) { ( Some(end), None, None ) => { Self { end: end.as_ref(), .. Default::default() } }, ( Some(start), Some(end), None ) => { Self { end: end.as_ref(), start: Some(start.as_ref()), ..Default::default() } }, ( Some(start), Some(increment), Some(end) ) => { Self { end: end.as_ref(), start: Some(start.as_ref()), increment: Some(increment.as_ref()), ..Default::default() } }, _ => panic!("More than one positional argument is required") }; Ok(o) } } impl TryFrom<&mut Args> for letter_sequence::SequenceBuilder { type Error = letter_sequence::SequenceError; fn try_from(args: &mut Args) -> Result { let positional_args: Vec = std::mem::take(&mut args.args); let positional_args: Vec<&str> = positional_args.iter().map(AsRef::as_ref).collect(); let positional_args: &[&str] = positional_args.as_slice(); let positional_args = PositionalArgs::try_from(positional_args).unwrap(); use letter_sequence::SequenceBuilder; let step = positional_args .increment .map_or( Ok(1), |x| x.parse::() )?; let builder = match (positional_args.start, positional_args.end) { (Some(start), end) => SequenceBuilder::try_from( (start,end) ), (None, end) => SequenceBuilder::try_from( ("1", end) ), }.unwrap().inclusive().step(step); Ok(builder) } } /// Usage: seq [OPTION]... LAST /// or: seq [OPTION]... FIRST LAST /// or: seq [OPTION]... FIRST INCREMENT LAST /// /// Print numbers from FIRST to LAST, in steps of INCREMENT. /// /// If FIRST or INCREMENT is omitted, it defaults to 1. That is, an /// omitted INCREMENT defaults to 1 even when LAST is smaller than FIRST. /// The sequence of numbers ends when the sum of the current number and /// INCREMENT would become greater than LAST. /// FIRST, INCREMENT, and LAST are interpreted as floating point values. /// INCREMENT is usually positive if FIRST is smaller than LAST, and /// INCREMENT is usually negative if FIRST is greater than LAST. /// INCREMENT must not be 0; none of FIRST, INCREMENT and LAST may be NaN. /// FORMAT must be suitable for printing one argument of type 'double'; /// it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point /// decimal numbers with maximum precision PREC, and to %g otherwise. #[derive(Parser, Debug)] #[clap(author, version, about)] struct Args { /// use printf style floating-point FORMAT #[clap(short, long)] format: Option, /// use STRING to separate numbers (default: \n) #[clap(short, long)] seperator: Option, /// equalize width by padding with leading zeroes #[clap(short = 'w', long)] equal_width: Option, #[clap(required=true)] args: Vec, } fn main() -> Result<(), Box> { let mut opts = Args::from_args(); let mut seq = letter_sequence::SequenceBuilder::try_from(&mut opts)? .build()?; let sep = opts .seperator .unwrap_or("\n".to_string()); let mut first = true; for e in seq { if ( first ) { print!("{}", e); first = false; } else { print!("{}{}", sep, e); } } print!("\n"); Ok(()) }