overload/
overload.rs

1use anyhow::{self, Context};
2use mini_async_repl::{
3    command::{
4        lift_validation_err, validate, ArgsError, Command, CommandArgInfo, CommandArgType,
5        ExecuteCommand,
6    },
7    CommandStatus, Repl,
8};
9use std::future::Future;
10use std::pin::Pin;
11
12struct DescribeCommandHandler {}
13impl DescribeCommandHandler {
14    pub fn new() -> Self {
15        Self {}
16    }
17    async fn handle_variant_1(&mut self) -> anyhow::Result<CommandStatus> {
18        println!("No arguments");
19        Ok(CommandStatus::Done)
20    }
21    async fn handle_variant_2(&mut self, a: i32, b: i32) -> anyhow::Result<CommandStatus> {
22        println!("Got two integers: {} {}", a, b);
23        Ok(CommandStatus::Done)
24    }
25    async fn handle_variant_3(&mut self, a: i32, b: String) -> anyhow::Result<CommandStatus> {
26        println!("An integer `{}` and a string `{}`", a, b);
27        Ok(CommandStatus::Done)
28    }
29}
30impl ExecuteCommand for DescribeCommandHandler {
31    fn execute(
32        &mut self,
33        args: Vec<String>,
34        args_info: Vec<CommandArgInfo>,
35    ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
36        let valid = validate(args.clone(), args_info.clone());
37        if let Err(e) = valid {
38            return Box::pin(lift_validation_err(Err(e)));
39        }
40
41        // Note: this example could also be implemented by
42        // providing one CommandHandler for each overload.
43        // For now I think it's better not to constraint approaches
44        // because it's not yet clear to me what the best design is.
45        let variant_1 = validate(args.clone(), args_info);
46        if let Ok(()) = variant_1 {
47            return Box::pin(self.handle_variant_1());
48        }
49
50        let variant_2 = validate(
51            args.clone(),
52            vec![
53                CommandArgInfo::new_with_name(CommandArgType::I32, "a"),
54                CommandArgInfo::new_with_name(CommandArgType::I32, "b"),
55            ],
56        );
57        if let Ok(()) = variant_2 {
58            let a = args[0].parse::<i32>();
59            let b = args[1].parse::<i32>();
60
61            match (a, b) {
62                (Ok(a), Ok(b)) => {
63                    return Box::pin(self.handle_variant_2(a, b));
64                }
65                _ => (),
66            }
67        }
68
69        let variant_3 = validate(
70            args.clone(),
71            vec![
72                CommandArgInfo::new_with_name(CommandArgType::I32, "a"),
73                CommandArgInfo::new_with_name(CommandArgType::String, "b"),
74            ],
75        );
76        if let Ok(()) = variant_3 {
77            let a = args[0].parse::<i32>();
78            let b = args[1].clone();
79
80            match a {
81                Ok(a) => {
82                    return Box::pin(self.handle_variant_3(a, b));
83                }
84                _ => (),
85            }
86        }
87
88        Box::pin(lift_validation_err(Err(ArgsError::NoVariantFound)))
89    }
90}
91
92#[tokio::main]
93async fn main() -> anyhow::Result<()> {
94    #[rustfmt::skip]
95    let mut repl = Repl::builder()
96        .add("describe", Command::new(
97            "Variant 1",
98            vec![],
99            Box::new(DescribeCommandHandler::new()),
100        ))
101        .add("describe", Command::new(
102        	"Variant 2",
103        	vec![
104        		CommandArgInfo::new_with_name(CommandArgType::I32, "a"),
105        		CommandArgInfo::new_with_name(CommandArgType::I32, "b"),
106        	],
107        	Box::new(DescribeCommandHandler::new()),
108        ))           
109        .add("describe", Command::new(
110            "Variant 3",
111            vec![
112        		CommandArgInfo::new_with_name(CommandArgType::I32, "a"),
113        		CommandArgInfo::new_with_name(CommandArgType::String, "b"),
114        	],
115        	Box::new(DescribeCommandHandler::new()),
116        ))
117        .build()
118        .context("Failed to create repl")?;
119
120    repl.run().await.context("Critical REPL error")?;
121
122    Ok(())
123}