cmdparse 0.1.1

Parsing user's commands into arbitrary Rust types
Documentation
use cmdparse::error::ParseError;
use cmdparse::parsers::{ParsableTransformation, TransformParser};
use cmdparse::{parse_parser, Parsable};
use rustyline::error::ReadlineError;
use rustyline::Editor;

#[derive(Debug, Parsable)]
enum Expression {
    #[cmd(transparent)]
    Value(f64),
    #[cmd(rename = "+")]
    Add(
        #[cmd(parser = "EvaluationParser")] f64,
        #[cmd(parser = "EvaluationParser")] f64,
    ),
    #[cmd(rename = "-")]
    Subtract(
        #[cmd(parser = "EvaluationParser")] f64,
        #[cmd(parser = "EvaluationParser")] f64,
    ),
    #[cmd(rename = "*")]
    Multiply(
        #[cmd(parser = "EvaluationParser")] f64,
        #[cmd(parser = "EvaluationParser")] f64,
    ),
    #[cmd(rename = "/")]
    Divide(
        #[cmd(parser = "EvaluationParser")] f64,
        #[cmd(parser = "EvaluationParser")] f64,
    ),
    Sqrt(#[cmd(parser = "EvaluationParser")] f64),
}

impl ParsableTransformation<f64> for Expression {
    type Input = Expression;

    fn transform(input: Self::Input) -> Result<f64, ParseError<'static>> {
        match input {
            Expression::Value(value) => Ok(value),
            Expression::Add(a, b) => Ok(a + b),
            Expression::Subtract(a, b) => Ok(a - b),
            Expression::Multiply(a, b) => Ok(a * b),
            Expression::Divide(_, b) if b == 0.0 => {
                Err(ParseError::custom("cannot divide by zero"))
            }
            Expression::Divide(a, b) => Ok(a / b),
            Expression::Sqrt(a) if a < 0.0 => Err(ParseError::custom(
                "cannot take square root of a negative number",
            )),
            Expression::Sqrt(a) => Ok(a.sqrt()),
        }
    }
}

type EvaluationParser = TransformParser<ExpressionParser, Expression, f64>;

fn main() {
    let mut rl = Editor::<()>::new();
    loop {
        let readline = rl.readline(">> ");
        match readline {
            Ok(line) => match parse_parser::<_, EvaluationParser>(&line, ()) {
                Ok(value) => println!("<< {}", value),
                Err(err) => println!("Error: {}", err),
            },
            Err(ReadlineError::Interrupted | ReadlineError::Eof) => break,
            Err(err) => {
                println!("Error: {}", err);
                break;
            }
        }
    }
}