1use std::net::IpAddr;
2use std::path::PathBuf;
3
4use anyhow::{self, Context};
5use mini_async_repl::{
6 command::{
7 lift_validation_err, validate, ArgsError, Command, CommandArgInfo, CommandArgType,
8 ExecuteCommand,
9 },
10 CommandStatus, Repl,
11};
12use std::future::Future;
13use std::pin::Pin;
14
15struct LsCommandHandler {}
16impl LsCommandHandler {
17 pub fn new() -> Self {
18 Self {}
19 }
20 async fn handle_command(&mut self, dir: PathBuf) -> anyhow::Result<CommandStatus> {
21 for entry in dir.read_dir()? {
22 println!("{}", entry?.path().to_string_lossy());
23 }
24 Ok(CommandStatus::Done)
25 }
26}
27impl ExecuteCommand for LsCommandHandler {
28 fn execute(
29 &mut self,
30 args: Vec<String>,
31 args_info: Vec<CommandArgInfo>,
32 ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
33 let valid = validate(args.clone(), args_info.clone());
34 if let Err(e) = valid {
35 return Box::pin(lift_validation_err(Err(e)));
36 }
37
38 let dir_buf: PathBuf = args[0].clone().into();
39 Box::pin(self.handle_command(dir_buf))
40 }
41}
42
43struct IpAddrCommandHandler {}
44impl IpAddrCommandHandler {
45 pub fn new() -> Self {
46 Self {}
47 }
48 async fn handle_command(&mut self, ip: IpAddr) -> anyhow::Result<CommandStatus> {
49 println!("{}", ip);
50 Ok(CommandStatus::Done)
51 }
52}
53impl ExecuteCommand for IpAddrCommandHandler {
54 fn execute(
55 &mut self,
56 args: Vec<String>,
57 args_info: Vec<CommandArgInfo>,
58 ) -> Pin<Box<dyn Future<Output = anyhow::Result<CommandStatus>> + '_>> {
59 let valid = validate(args.clone(), args_info.clone());
60 if let Err(e) = valid {
61 return Box::pin(lift_validation_err(Err(e)));
62 }
63
64 let ip = args[0].parse();
65
66 match ip {
67 Ok(ip) => Box::pin(self.handle_command(ip)),
68 Err(e) => Box::pin(lift_validation_err(Err(ArgsError::WrongArgumentValue {
69 argument: args[0].clone(),
70 error: e.to_string(),
71 }))),
72 }
73 }
74}
75
76#[tokio::main]
77async fn main() -> anyhow::Result<()> {
78 #[rustfmt::skip]
79 let mut repl = Repl::builder()
80 .add("ls", Command::new(
81 "List files in a directory",
82 vec![CommandArgInfo::new_with_name(CommandArgType::Custom, "dir")],
83 Box::new(LsCommandHandler::new()),
84 ))
85 .add("ipaddr", Command::new(
86 "Just parse and print the given IP address".into(),
87 vec![CommandArgInfo::new_with_name(CommandArgType::Custom, "ip")],
88 Box::new(IpAddrCommandHandler::new()),
89 ))
90 .build()
91 .context("Failed to create repl")?;
92
93 repl.run().await.context("Critical REPL error")
94}