You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.6 KiB

//! Parsing args
use super::*;
use ext::*;
use std::iter;
/// Arg state
#[derive(Debug, Default)]
struct State
{
is_server: bool,
is_sending: bool,
enc: Option<bool>,
comp: Option<bool>,
bufsz: Option<usize>,
arc: Option<bool>,
contin: Option<bool>,
oneshot: Option<bool>,
inter: Option<bool>,
files: Vec<String>,
}
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<I>(state: &mut State, single: I) -> eyre::Result<()>
where I: IntoIterator<Item=char>
{
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<I>(args: &mut I) -> eyre::Result<Op>
where I: Iterator<Item= String> + ?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<State> for Op`, etc")
}
fn parse_iter_raw<I>(args: &mut I) -> eyre::Result<State>
where I: Iterator<Item= String> + ?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)
}