minimal/
minimal.rs

1use anyhow::{self, Context};
2use mini_async_repl::{
3    command::{
4        lift_validation_err, validate, Command, CommandArgInfo, CommandArgType, ExecuteCommand,
5    },
6    CommandStatus, Repl,
7};
8use std::future::Future;
9use std::pin::Pin;
10
11struct SayHelloCommandHandler {}
12impl SayHelloCommandHandler {
13    pub fn new() -> Self {
14        Self {}
15    }
16    async fn handle_command(&mut self, name: String) -> anyhow::Result<CommandStatus> {
17        println!("Hello {}!", name);
18        Ok(CommandStatus::Done)
19    }
20}
21impl ExecuteCommand for SayHelloCommandHandler {
22    fn execute(
23        &mut self,
24        args: Vec<String>,
25        args_info: Vec<CommandArgInfo>,
26    ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
27        let valid = validate(args.clone(), args_info.clone());
28        if valid.is_err() {
29            return Box::pin(lift_validation_err(valid));
30        }
31        Box::pin(self.handle_command(args[0].clone()))
32    }
33}
34
35struct AddCommandHandler {}
36impl AddCommandHandler {
37    pub fn new() -> Self {
38        Self {}
39    }
40    async fn handle_command(&mut self, x: i32, y: i32) -> anyhow::Result<CommandStatus> {
41        println!("{} + {} = {}", x, y, x + y);
42        Ok(CommandStatus::Done)
43    }
44}
45impl ExecuteCommand for AddCommandHandler {
46    fn execute(
47        &mut self,
48        args: Vec<String>,
49        args_info: Vec<CommandArgInfo>,
50    ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
51        let valid = validate(args.clone(), args_info.clone());
52        if valid.is_err() {
53            return Box::pin(lift_validation_err(valid));
54        }
55
56        let x = args[0].parse::<i32>();
57        let y = args[1].parse::<i32>();
58
59        match (x, y) {
60            (Ok(x), Ok(y)) => Box::pin(self.handle_command(x, y)),
61            _ => panic!("Unreachable, validator should have covered this"),
62        }
63    }
64}
65
66#[tokio::main]
67async fn main() -> anyhow::Result<()> {
68    let hello_cmd = Command::new(
69        "Say hello",
70        vec![CommandArgInfo::new_with_name(
71            CommandArgType::String,
72            "name",
73        )],
74        Box::new(SayHelloCommandHandler::new()),
75    );
76
77    let add_cmd = Command::new(
78        "Add X to Y",
79        vec![
80            CommandArgInfo::new_with_name(CommandArgType::I32, "X"),
81            CommandArgInfo::new_with_name(CommandArgType::I32, "Y"),
82        ],
83        Box::new(AddCommandHandler::new()),
84    );
85
86    #[rustfmt::skip]
87    let mut repl = Repl::builder()
88        .add("hello", hello_cmd)
89        .add("add", add_cmd)
90        .build()
91        .context("Failed to create repl")?;
92
93    repl.run().await.context("Critical REPL error")?;
94
95    Ok(())
96}