from_str/
from_str.rs

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}