//! Parsing args use super::*; use ext::*; use std::iter; /// Arg state #[derive(Debug, Default)] struct State { is_server: bool, is_sending: bool, enc: Option, comp: Option, bufsz: Option, arc: Option, contin: Option, oneshot: Option, inter: Option, files: Vec, } impl State { fn mode(&self) -> impl fmt::Display + 'static { let send = r#if!(self.is_sending, "send", "recv"); let serve = r#if!(self.is_server, "server", "client"); lazy_format!("{} ({})", send, serve) } } fn parse_schain(state: &mut State, single: I) -> eyre::Result<()> where I: IntoIterator { for ch in single.into_iter().map(char::to_lowercase).flatten() { match ch { 'e' => state.enc = Some(true), 'c' => state.comp = Some(true), 'a' => state.arc = Some(true), 'k' => state.contin = Some(true), '1' if state.is_server => state.oneshot = Some(true), 'i' if !state.is_sending => state.inter = Some(true), x => return Err(eyre!("Unknown option for mode {}", state.mode())) .with_section(move || x.header("Option was")) .with_note(move || "Some options are only valid for certain modes"), } } Ok(()) } /// Try to parse an iterator of strings (usually the command-line arguments) into an `Op`. pub fn parse_iter(args: &mut I) -> eyre::Result where I: Iterator + ?Sized { let state = parse_iter_raw(args) .wrap_err(eyre!("Invalid arguments")) .with_suggestion(|| "Try passing `--help`")?; // Send help message here, since it's unlikely to be helpful when returning from state's validation compared to here. todo!("TODO: `impl TryFrom for Op`, etc") } fn parse_iter_raw(args: &mut I) -> eyre::Result where I: Iterator + ?Sized { let mut state = State::default(); //TODO: Parse modes before this. while let Some(arg) = args.next() { let mut chars = arg.chars(); match (&mut chars).take(2).collect_array::<2>() { ['-', '-'] => { // Long option let opt = &arg[2..]; match opt { "--" => break, //TODO: Long options, pulling option param from `args` if needed, etc. unknown => return Err(eyre!("Unknown option for mode {}", state.mode())) .with_section(|| format!("--{}", unknown).header("Option was")) .with_note(|| "Some options are only valid for certain modes"), } }, ['-', n] => { // Small option parse_schain(&mut state, iter::once(n).chain(chars))?; }, _ => { // Not an option state.files.push(arg); }, } } Ok(state) }