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::cell::RefCell;
9use std::future::Future;
10use std::pin::Pin;
11use std::rc::Rc;
12
13struct CountCommandHandler {}
14impl CountCommandHandler {
15 pub fn new() -> Self {
16 Self {}
17 }
18 async fn handle_command(&mut self, x: i32, y: i32) -> anyhow::Result<CommandStatus> {
19 for i in x..=y {
20 print!(" {}", i);
21 }
22 println!();
23 Ok(CommandStatus::Done)
24 }
25}
26impl ExecuteCommand for CountCommandHandler {
27 fn execute(
28 &mut self,
29 args: Vec<String>,
30 args_info: Vec<CommandArgInfo>,
31 ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
32 let valid = validate(args.clone(), args_info.clone());
33 if let Err(e) = valid {
34 return Box::pin(lift_validation_err(Err(e)));
35 }
36
37 let x = args[0].parse::<i32>();
38 let y = args[1].parse::<i32>();
39
40 match (x, y) {
41 (Ok(x), Ok(y)) => Box::pin(self.handle_command(x, y)),
42 _ => panic!("Unreachable, validator should have covered this"),
43 }
44 }
45}
46
47struct SayCommandHandler {}
48impl SayCommandHandler {
49 pub fn new() -> Self {
50 Self {}
51 }
52 async fn handle_command(&mut self, x: f32) -> anyhow::Result<CommandStatus> {
53 println!("x is equal to {}", x);
54 Ok(CommandStatus::Done)
55 }
56}
57impl ExecuteCommand for SayCommandHandler {
58 fn execute(
59 &mut self,
60 args: Vec<String>,
61 args_info: Vec<CommandArgInfo>,
62 ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
63 let valid = validate(args.clone(), args_info.clone());
64 if let Err(e) = valid {
65 return Box::pin(lift_validation_err(Err(e)));
66 }
67
68 let x = args[0].parse::<f32>();
69 match x {
70 Ok(x) => Box::pin(self.handle_command(x)),
71 _ => panic!("Unreachable, validator should have covered this"),
72 }
73 }
74}
75
76struct OutXCommandHandler {
77 outside_x: Rc<RefCell<String>>,
78}
79impl OutXCommandHandler {
80 pub fn new(outside_x: Rc<RefCell<String>>) -> Self {
81 Self { outside_x }
82 }
83 async fn handle_command(&mut self) -> anyhow::Result<CommandStatus> {
84 let mut x = self.outside_x.borrow_mut();
85 *x += "x";
86 println!("{}", x);
87 Ok(CommandStatus::Done)
88 }
89}
90impl ExecuteCommand for OutXCommandHandler {
91 fn execute(
92 &mut self,
93 args: Vec<String>,
94 args_info: Vec<CommandArgInfo>,
95 ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
96 let valid = validate(args.clone(), args_info.clone());
97 if let Err(e) = valid {
98 return Box::pin(lift_validation_err(Err(e)));
99 }
100 Box::pin(self.handle_command())
101 }
102}
103
104#[tokio::main]
105async fn main() -> anyhow::Result<()> {
106 let outside_x = Rc::new(RefCell::new(String::from("Out x")));
107
108 #[rustfmt::skip]
109 let mut repl = Repl::builder()
110 .description("Example REPL")
111 .prompt("=> ")
112 .text_width(60 as usize)
113 .add("count", Command::new(
114 "Count from X to Y",
115 vec![
116 CommandArgInfo::new_with_name(CommandArgType::I32, "X"),
117 CommandArgInfo::new_with_name(CommandArgType::I32, "Y"),
118 ],
119 Box::new(CountCommandHandler::new()),
120 ))
121 .add("say", Command::new(
122 "Say X",
123 vec![CommandArgInfo::new_with_name(CommandArgType::F32, "X")],
124 Box::new(SayCommandHandler::new()),
125 ))
126 .add("outx", Command::new(
127 "Use mutably outside var x. This command has a really long description so we need to wrap it somehow, it is interesting how actually the wrapping will be performed.",
128 vec![],
129 Box::new(OutXCommandHandler::new(outside_x.clone())),
130 ))
131 .build().context("Failed to create repl")?;
132
133 repl.run().await.context("Critical REPL error")?;
134
135 Ok(())
136}