use std::{error::Error, fmt::Display};
#[cfg_attr(nightly, doc(cfg(feature = "async")))]
#[cfg(feature = "async")]
use async_recursion::async_recursion;
use crate::{Command, FnType};
#[derive(Debug)]
struct AsyncHandleError {}
impl Display for AsyncHandleError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Tried to use async callback with sync handler!")
}
}
impl Error for AsyncHandleError {}
impl<'a, T: Send> Command<'a, T> {
pub fn handle(&self, state: &mut T, prompt: &[&str]) -> Result<(), Box<dyn Error>> {
if let Some(cmd) = prompt.first() {
if let Some(subcommand) = self.subcommands.get(cmd) {
return subcommand.handle(state, &prompt[1..prompt.len()]);
}
}
match self.callback {
FnType::Sync(f) => (f)(state, prompt.iter().map(|a| a.to_string()).collect()),
#[cfg_attr(nightly, doc(cfg(feature = "async")))]
#[cfg(feature = "async")]
FnType::Async(_) => Err(Box::new(AsyncHandleError {})),
}
}
#[cfg_attr(nightly, doc(cfg(feature = "async")))]
#[cfg(feature = "async")]
#[async_recursion]
pub async fn handle_async(&self, state: &mut T, prompt: &[&str]) -> Result<(), Box<dyn Error>> {
if let Some(cmd) = prompt.first() {
if let Some(subcommand) = self.subcommands.get(cmd) {
return subcommand
.handle_async(state, &prompt[1..prompt.len()])
.await;
}
}
match self.callback {
FnType::Sync(f) => (f)(state, prompt.iter().map(|a| a.to_string()).collect()),
FnType::Async(f) => (f)(state, prompt.iter().map(|a| a.to_string()).collect()).await,
}
}
pub fn add_subcommand(&mut self, command: Command<'a, T>) -> Option<Command<'_, T>> {
self.subcommands.insert(command.name, command)
}
pub fn info(&self, f: &mut std::fmt::Formatter<'_>, depth: usize) -> std::fmt::Result {
let indent = "| ".repeat(depth);
let string = format!("{}|-- {} ", indent, self.name);
writeln!(f, "{:.<35} {}", string, self.help)?;
for c in &self.subcommands {
c.1.info(f, depth + 1)?;
}
Ok(())
}
}