pub mod arguments;
pub mod context;
pub mod errors;
pub mod parsing;
pub mod prefixes;
pub(crate) mod routing;
use std::error::Error;
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;
use twilight_gateway::Event;
use crate::commands::errors::CommandError;
use crate::commands::permissions::{PermissionChecker, PermissionContext};
use crate::commands::prefixed::arguments::IntoArgument;
use crate::commands::prefixed::context::PrefixedContext;
use crate::commands::{CommandGroupIntoCommandNode, CommandNode, CommandResult};
use crate::errors::{ErrorHandler, ErrorHandlerWithoutType, ErrorHandlerWrapper};
use crate::state::StateBound;
use crate::utils::DynFuture;
pub trait IntoAliases {
fn into_aliases(self) -> Vec<String>;
}
impl IntoAliases for String {
fn into_aliases(self) -> Vec<String> {
vec![self]
}
}
impl IntoAliases for &str {
fn into_aliases(self) -> Vec<String> {
vec![self.to_string()]
}
}
impl IntoAliases for Vec<String> {
fn into_aliases(self) -> Vec<String> {
self
}
}
impl IntoAliases for Vec<&str> {
fn into_aliases(self) -> Vec<String> {
self.into_iter().map(|s| s.to_string()).collect()
}
}
impl IntoAliases for &[&str] {
fn into_aliases(self) -> Vec<String> {
self.iter().map(|s| s.to_string()).collect()
}
}
impl<const N: usize> IntoAliases for [&str; N] {
fn into_aliases(self) -> Vec<String> {
self.iter().map(|s| s.to_string()).collect()
}
}
#[derive(Clone)]
pub struct PrefixedCommand<State>
where
State: StateBound,
{
pub name: String,
pub aliases: Vec<String>,
pub summary: Option<String>,
pub description: Option<String>,
pub(crate) handler: Arc<dyn PrefixedCommandHandlerWithoutArgs<State>>,
pub(crate) on_errors: Vec<Arc<dyn ErrorHandlerWithoutType<State>>>,
pub(crate) checks: Vec<Arc<dyn PermissionChecker<State>>>,
}
impl<State> PrefixedCommand<State>
where
State: StateBound,
{
pub fn build<F, Args>(name: impl Into<String>, handler: F) -> PrefixedCommandBuilder<State>
where
F: PrefixedCommandHandler<State, Args> + 'static,
Args: Send + Sync + 'static,
{
PrefixedCommandBuilder::new(name, handler)
}
pub fn identifiers(&self) -> Vec<String> {
let mut identifiers = vec![self.name.clone()];
identifiers.extend(self.aliases.clone());
identifiers
}
pub(crate) async fn run(&self, ctx: PrefixedContext<State>, args: &str) -> CommandResult {
let permission_ctx = PermissionContext {
event: Event::MessageCreate(Box::new(ctx.event.clone())),
handle: ctx.handle.clone(),
state: ctx.state.clone(),
};
for checker in &self.checks {
checker.check(permission_ctx.clone()).await.map_err(CommandError::Permissions)?;
}
self.handler.run(ctx, args).await
}
}
pub struct PrefixedCommandBuilder<State>
where
State: StateBound,
{
name: String,
aliases: Vec<String>,
summary: Option<String>,
description: Option<String>,
handler: Arc<dyn PrefixedCommandHandlerWithoutArgs<State>>,
on_errors: Vec<Arc<dyn ErrorHandlerWithoutType<State>>>,
checks: Vec<Arc<dyn PermissionChecker<State>>>,
}
impl<State> PrefixedCommandBuilder<State>
where
State: StateBound,
{
pub(crate) fn new<F, Args>(name: impl Into<String>, handler: F) -> Self
where
F: PrefixedCommandHandler<State, Args> + 'static,
Args: Send + Sync + 'static,
{
let wrapper = PrefixedCommandHandlerWrapper::new(handler);
PrefixedCommandBuilder {
name: name.into(),
aliases: Vec::new(),
summary: None,
description: None,
handler: Arc::new(wrapper),
on_errors: Vec::new(),
checks: Vec::new(),
}
}
pub fn aliases(mut self, aliases: impl IntoAliases) -> Self {
self.aliases = aliases.into_aliases();
self
}
pub fn summary(mut self, summary: impl Into<String>) -> Self {
self.summary = Some(summary.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn on_error<F, Error>(mut self, handler: F) -> Self
where
F: ErrorHandler<State, Error> + 'static,
Error: Send + Sync + 'static,
{
self.on_errors
.push(Arc::new(ErrorHandlerWrapper::new(handler)));
self
}
pub fn check<F>(mut self, handler: F) -> Self
where
F: PermissionChecker<State> + 'static,
{
self.checks.push(Arc::new(handler));
self
}
pub(crate) fn build(self) -> PrefixedCommand<State> {
PrefixedCommand {
name: self.name,
aliases: self.aliases,
summary: self.summary,
description: self.description,
handler: self.handler,
on_errors: self.on_errors,
checks: self.checks,
}
}
}
pub trait IntoCommandResult {
fn into_command_result(self) -> Result<(), CommandError>;
}
impl IntoCommandResult for () {
fn into_command_result(self) -> Result<(), CommandError> {
Ok(())
}
}
impl<T, E> IntoCommandResult for Result<T, E>
where
E: Error + Send + Sync + 'static,
{
fn into_command_result(self) -> Result<(), CommandError> {
match self {
Ok(_) => Ok(()),
Err(err) => Err(CommandError::Runtime(Arc::new(err))),
}
}
}
pub trait PrefixedCommandHandler<State, Args>: Send + Sync
where
State: StateBound,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult>;
}
impl<State, F, Fut, Res> PrefixedCommandHandler<State, ()> for F
where
F: Fn(PrefixedContext<State>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
{
fn run(&self, ctx: PrefixedContext<State>, _args: &str) -> DynFuture<'_, CommandResult> {
Box::pin(async move { self(ctx).await.into_command_result() })
}
}
impl<State, Func, Fut, A, Res> PrefixedCommandHandler<State, (A,)> for Func
where
Func: Fn(PrefixedContext<State>, A) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
A: IntoArgument<State> + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
let args = args.to_string();
Box::pin(async move {
let (a, _remaining) = A::into_argument(ctx.clone(), args).await?;
self(ctx, a).await.into_command_result()
})
}
}
impl<State, Func, Fut, A, B, Res> PrefixedCommandHandler<State, (A, B)> for Func
where
Func: Fn(PrefixedContext<State>, A, B) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
A: IntoArgument<State> + 'static,
B: IntoArgument<State> + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
let args = args.to_string();
Box::pin(async move {
let (a, remaining) = A::into_argument(ctx.clone(), args).await?;
let (b, _remaining) = B::into_argument(ctx.clone(), remaining).await?;
self(ctx, a, b).await.into_command_result()
})
}
}
impl<State, Func, Fut, A, B, C, Res> PrefixedCommandHandler<State, (A, B, C)> for Func
where
Func: Fn(PrefixedContext<State>, A, B, C) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
A: IntoArgument<State> + 'static,
B: IntoArgument<State> + 'static,
C: IntoArgument<State> + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
let args = args.to_string();
Box::pin(async move {
let (a, remaining) = A::into_argument(ctx.clone(), args).await?;
let (b, remaining) = B::into_argument(ctx.clone(), remaining).await?;
let (c, _remaining) = C::into_argument(ctx.clone(), remaining).await?;
self(ctx, a, b, c).await.into_command_result()
})
}
}
impl<State, Func, Fut, A, B, C, D, Res> PrefixedCommandHandler<State, (A, B, C, D)> for Func
where
Func: Fn(PrefixedContext<State>, A, B, C, D) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
A: IntoArgument<State> + 'static,
B: IntoArgument<State> + 'static,
C: IntoArgument<State> + 'static,
D: IntoArgument<State> + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
let args = args.to_string();
Box::pin(async move {
let (a, remaining) = A::into_argument(ctx.clone(), args).await?;
let (b, remaining) = B::into_argument(ctx.clone(), remaining).await?;
let (c, remaining) = C::into_argument(ctx.clone(), remaining).await?;
let (d, _remaining) = D::into_argument(ctx.clone(), remaining).await?;
self(ctx, a, b, c, d).await.into_command_result()
})
}
}
impl<State, Func, Fut, A, B, C, D, E, Res> PrefixedCommandHandler<State, (A, B, C, D, E)> for Func
where
Func: Fn(PrefixedContext<State>, A, B, C, D, E) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
A: IntoArgument<State> + 'static,
B: IntoArgument<State> + 'static,
C: IntoArgument<State> + 'static,
D: IntoArgument<State> + 'static,
E: IntoArgument<State> + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
let args = args.to_string();
Box::pin(async move {
let (a, remaining) = A::into_argument(ctx.clone(), args).await?;
let (b, remaining) = B::into_argument(ctx.clone(), remaining).await?;
let (c, remaining) = C::into_argument(ctx.clone(), remaining).await?;
let (d, remaining) = D::into_argument(ctx.clone(), remaining).await?;
let (e, _remaining) = E::into_argument(ctx.clone(), remaining).await?;
self(ctx, a, b, c, d, e).await.into_command_result()
})
}
}
impl<State, Func, Fut, A, B, C, D, E, F, Res> PrefixedCommandHandler<State, (A, B, C, D, E, F)>
for Func
where
Func: Fn(PrefixedContext<State>, A, B, C, D, E, F) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Res> + Send + 'static,
Res: IntoCommandResult + Send + 'static,
State: StateBound,
A: IntoArgument<State> + 'static,
B: IntoArgument<State> + 'static,
C: IntoArgument<State> + 'static,
D: IntoArgument<State> + 'static,
E: IntoArgument<State> + 'static,
F: IntoArgument<State> + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
let args = args.to_string();
Box::pin(async move {
let (a, remaining) = A::into_argument(ctx.clone(), args).await?;
let (b, remaining) = B::into_argument(ctx.clone(), remaining).await?;
let (c, remaining) = C::into_argument(ctx.clone(), remaining).await?;
let (d, remaining) = D::into_argument(ctx.clone(), remaining).await?;
let (e, remaining) = E::into_argument(ctx.clone(), remaining).await?;
let (f, _remaining) = F::into_argument(ctx.clone(), remaining).await?;
self(ctx, a, b, c, d, e, f).await.into_command_result()
})
}
}
struct PrefixedCommandHandlerWrapper<F, Args> {
handler: F,
_args: PhantomData<Args>,
}
impl<F, Args> PrefixedCommandHandlerWrapper<F, Args> {
fn new(handler: F) -> Self {
PrefixedCommandHandlerWrapper {
handler,
_args: PhantomData,
}
}
}
pub trait PrefixedCommandHandlerWithoutArgs<State>: Send + Sync
where
State: StateBound,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult>;
}
impl<State, F, Args> PrefixedCommandHandlerWithoutArgs<State>
for PrefixedCommandHandlerWrapper<F, Args>
where
State: StateBound,
F: PrefixedCommandHandler<State, Args>,
Args: Send + Sync + 'static,
{
fn run(&self, ctx: PrefixedContext<State>, args: &str) -> DynFuture<'_, CommandResult> {
self.handler.run(ctx, args)
}
}
#[derive(Clone)]
pub struct PrefixedCommandGroup<State>
where
State: StateBound,
{
pub name: String,
pub summary: Option<String>,
pub description: Option<String>,
pub children: Vec<CommandNode<State>>,
pub(crate) on_errors: Vec<Arc<dyn ErrorHandlerWithoutType<State>>>,
}
impl<State> PrefixedCommandGroup<State>
where
State: StateBound,
{
pub fn build(name: impl Into<String>) -> PrefixedCommandGroupBuilder<State> {
PrefixedCommandGroupBuilder::new(name)
}
}
pub struct PrefixedCommandGroupBuilder<State>
where
State: StateBound,
{
name: String,
summary: Option<String>,
description: Option<String>,
children: Vec<CommandNode<State>>,
on_errors: Vec<Arc<dyn ErrorHandlerWithoutType<State>>>,
}
impl<State> PrefixedCommandGroupBuilder<State>
where
State: StateBound,
{
pub(crate) fn new(name: impl Into<String>) -> Self {
PrefixedCommandGroupBuilder {
name: name.into(),
summary: None,
description: None,
children: Vec::new(),
on_errors: Vec::new(),
}
}
pub fn summary(mut self, summary: impl Into<String>) -> Self {
self.summary = Some(summary.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn command(mut self, command: PrefixedCommandBuilder<State>) -> Self {
self.children
.push(CommandNode::PrefixedCommand(command.build()));
self
}
pub fn nest(mut self, group: PrefixedCommandGroupBuilder<State>) -> Self {
self.children
.push(CommandNode::PrefixedCommandGroup(group.build()));
self
}
pub fn on_error<F, Dummy, Error>(mut self, handler: F) -> Self
where
F: ErrorHandler<State, Error> + 'static,
Error: Send + Sync + 'static,
{
self.on_errors
.push(Arc::new(ErrorHandlerWrapper::new(handler)));
self
}
pub(crate) fn build(self) -> PrefixedCommandGroup<State> {
PrefixedCommandGroup {
name: self.name,
summary: self.summary,
description: self.description,
children: self.children,
on_errors: self.on_errors,
}
}
}
impl<State> CommandGroupIntoCommandNode<State> for PrefixedCommandGroup<State>
where
State: StateBound,
{
fn into_command_node(self) -> CommandNode<State> {
CommandNode::PrefixedCommandGroup(self)
}
}
impl<State> CommandGroupIntoCommandNode<State> for PrefixedCommandGroupBuilder<State>
where
State: StateBound,
{
fn into_command_node(self) -> CommandNode<State> {
CommandNode::PrefixedCommandGroup(self.build())
}
}