use std::{ fmt, ops::{Deref, DerefMut}, }; use thiserror::Error; #[derive(Debug, Error)] pub enum ArgumentParsingError { #[error("This argument was missing in the arguments array")] MissingArgument, #[error("An argument was there but it could not be parsed into the specified value")] InvalidArgument, } pub trait FromArguments: Sized { fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError>; } impl FromArguments for String { fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> { if !args.is_empty() { match args.split_once(" ") { Some((arg, rest)) => Ok((arg.to_string(), rest)), None => Ok((args.to_string(), "")), } } else { Ok((args.to_string(), "")) } } } /// Consumes the entire remaining string as a single argument. If no string is remaining, it /// returns an empty string. /// /// Parsing this argument type never fails. pub struct GreedyString(pub String); impl FromArguments for GreedyString { fn from_args<'a>(args: &str) -> Result<(Self, &str), ArgumentParsingError> { let value = GreedyString(args.to_string()); Ok((value, "")) } } impl Deref for GreedyString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for GreedyString { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl fmt::Display for GreedyString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } pub struct NeedyString(pub String); impl Deref for NeedyString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for NeedyString { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl fmt::Display for NeedyString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl FromArguments for NeedyString { fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> { if !args.is_empty() { match args.split_once(" ") { Some((arg, rest)) => Ok((Self(arg.to_string()), rest)), None => Ok((Self(args.to_string()), "")), } } else { Err(ArgumentParsingError::MissingArgument) } } } pub struct NeedyGreedyString(pub String); impl Deref for NeedyGreedyString { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for NeedyGreedyString { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl fmt::Display for NeedyGreedyString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } impl FromArguments for NeedyGreedyString { fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> { if !args.is_empty() { Ok((Self(args.to_string()), "")) } else { Err(ArgumentParsingError::MissingArgument) } } } impl FromArguments for bool { fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> { let arg: &str; let rest: &str; match args.split_once(" ") { Some((a, b)) => { arg = a; rest = b; } None => { arg = args; rest = ""; } } match arg { "y" | "yes" | "on" | "true" | "t" | "1" => Ok((true, rest)), "n" | "no" | "off" | "false" | "f" | "0" => Ok((false, rest)), _ => Err(ArgumentParsingError::InvalidArgument), } } } impl FromArguments for Option where T: FromArguments, { fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> { match T::from_args(args) { Ok((result, rest)) => Ok((Some(result), rest)), Err(_) => Ok((None, args)), } } } pub trait ParseArguments: Sized { fn parse(args: &str) -> Result; } impl ParseArguments for () { fn parse(_: &str) -> Result { Ok(()) } } impl ParseArguments for A where A: FromArguments, { fn parse(args: &str) -> Result { let (a, _) = A::from_args(args)?; Ok(a) } } impl ParseArguments for (A,) where A: FromArguments, { fn parse(args: &str) -> Result { let (a, _) = A::from_args(args)?; Ok((a,)) } } impl ParseArguments for (A, B) where A: FromArguments, B: FromArguments, { fn parse(args: &str) -> Result { let (a, args) = A::from_args(args)?; let (b, _) = B::from_args(args)?; Ok((a, b)) } } impl ParseArguments for (A, B, C) where A: FromArguments, B: FromArguments, C: FromArguments, { fn parse(args: &str) -> Result { let (a, args) = A::from_args(args)?; let (b, args) = B::from_args(args)?; let (c, _) = C::from_args(args)?; Ok((a, b, c)) } } pub struct Argument { pub name: &'static str, pub is_optional: bool, pub is_greedy: bool, } impl fmt::Display for Argument { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut argument = String::new(); if self.is_optional { argument.push('['); } else { argument.push('<'); } argument.push_str(self.name); if self.is_greedy { argument.push_str("..."); } if self.is_optional { argument.push(']'); } else { argument.push('>'); } write!(f, "{argument}") } }