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}