Files
payphone/src/framework/commands/arguments.rs
T

262 lines
5.8 KiB
Rust

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<T> FromArguments for Option<T>
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<Self, ArgumentParsingError>;
}
impl ParseArguments for () {
fn parse(_: &str) -> Result<Self, ArgumentParsingError> {
Ok(())
}
}
impl<A> ParseArguments for A
where
A: FromArguments,
{
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
let (a, _) = A::from_args(args)?;
Ok(a)
}
}
impl<A> ParseArguments for (A,)
where
A: FromArguments,
{
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
let (a, _) = A::from_args(args)?;
Ok((a,))
}
}
impl<A, B> ParseArguments for (A, B)
where
A: FromArguments,
B: FromArguments,
{
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
let (a, args) = A::from_args(args)?;
let (b, _) = B::from_args(args)?;
Ok((a, b))
}
}
impl<A, B, C> ParseArguments for (A, B, C)
where
A: FromArguments,
B: FromArguments,
C: FromArguments,
{
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
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}")
}
}