use crate::{
command::{Command, CommandMap},
framework::{DefaultError, Framework},
group::*,
hook::{AfterHook, BeforeHook},
twilight_exports::{ApplicationMarker, Client, Id, Permissions},
parse::ParseError
};
#[cfg(feature = "rc")]
use std::rc::Rc;
use std::{ops::Deref, sync::Arc};
#[allow(clippy::large_enum_variant)]
pub enum WrappedClient {
Arc(Arc<Client>),
#[cfg(feature = "rc")]
Rc(Rc<Client>),
Raw(Client),
Boxed(Box<dyn Deref<Target = Client> + Send + Sync>),
}
impl WrappedClient {
pub fn inner(&self) -> &Client {
match self {
Self::Arc(c) => c,
#[cfg(feature = "rc")]
Self::Rc(c) => &c,
Self::Raw(c) => c,
Self::Boxed(b) => b,
}
}
#[allow(clippy::needless_lifetimes, clippy::borrow_deref_ref)]
pub fn cast<'a, T>(&'a self) -> Option<&'a T> {
if let WrappedClient::Boxed(inner) = self {
let ptr = (&*inner.as_ref()) as *const _ as *const T;
Some(unsafe { &*ptr })
} else {
None
}
}
}
impl From<Client> for WrappedClient {
fn from(c: Client) -> Self {
WrappedClient::Raw(c)
}
}
impl From<Arc<Client>> for WrappedClient {
fn from(c: Arc<Client>) -> Self {
WrappedClient::Arc(c)
}
}
impl From<Box<dyn Deref<Target = Client> + Send + Sync>> for WrappedClient {
fn from(c: Box<dyn Deref<Target = Client> + Send + Sync>) -> Self {
Self::Boxed(c)
}
}
#[cfg(feature = "rc")]
impl From<Rc<Client>> for WrappedClient {
fn from(c: Rc<Client>) -> Self {
WrappedClient::Rc(c)
}
}
pub(crate) type FnPointer<T> = fn() -> T;
pub struct FrameworkBuilder<D, T = (), E = DefaultError> {
pub http_client: WrappedClient,
pub application_id: Id<ApplicationMarker>,
pub data: D,
pub commands: CommandMap<D, T, E>,
pub groups: ParentGroupMap<D, T, E>,
pub before: Option<BeforeHook<D>>,
pub after: Option<AfterHook<D, T, E>>,
}
impl<D, T, E> FrameworkBuilder<D, T, E>
where
E: From<ParseError>
{
pub fn new(
http_client: impl Into<WrappedClient>,
application_id: Id<ApplicationMarker>,
data: D,
) -> Self {
Self {
http_client: http_client.into(),
application_id,
data,
commands: Default::default(),
groups: Default::default(),
before: None,
after: None,
}
}
pub fn before(mut self, fun: FnPointer<BeforeHook<D>>) -> Self {
self.before = Some(fun());
self
}
pub fn after(mut self, fun: FnPointer<AfterHook<D, T, E>>) -> Self {
self.after = Some(fun());
self
}
pub fn command(mut self, fun: FnPointer<Command<D, T, E>>) -> Self {
let cmd = fun();
if self.commands.contains_key(cmd.name) || self.groups.contains_key(cmd.name) {
panic!("{} already registered", cmd.name);
}
self.commands.insert(cmd.name, cmd);
self
}
pub fn group<F>(mut self, fun: F) -> Self
where
F: FnOnce(&mut GroupParentBuilder<D, T, E>) -> &mut GroupParentBuilder<D, T, E>,
{
let mut builder = GroupParentBuilder::new();
fun(&mut builder);
let group = builder.build();
if self.commands.contains_key(group.name) || self.groups.contains_key(group.name) {
panic!("{} already registered", group.name);
}
self.groups.insert(group.name, group);
self
}
pub fn build(self) -> Framework<D, T, E> {
Framework::from_builder(self)
}
}
pub struct GroupParentBuilder<D, T, E> {
name: Option<&'static str>,
description: Option<&'static str>,
kind: ParentType<D, T, E>,
required_permissions: Option<Permissions>,
}
impl<D, T, E> GroupParentBuilder<D, T, E> {
pub(crate) fn new() -> Self {
Self {
name: None,
description: None,
kind: ParentType::Group(Default::default()),
required_permissions: None,
}
}
pub fn name(&mut self, name: &'static str) -> &mut Self {
self.name = Some(name);
self
}
pub fn description(&mut self, description: &'static str) -> &mut Self {
self.description = Some(description);
self
}
pub fn required_permissions(&mut self, permissions: Permissions) -> &mut Self {
self.required_permissions = Some(permissions);
self
}
pub fn group<F>(&mut self, fun: F) -> &mut Self
where
F: FnOnce(&mut CommandGroupBuilder<D, T, E>) -> &mut CommandGroupBuilder<D, T, E>,
{
let mut builder = CommandGroupBuilder::new();
fun(&mut builder);
let built = builder.build();
if let ParentType::Group(map) = &mut self.kind {
assert!(!map.contains_key(built.name));
map.insert(built.name, built);
} else {
let mut map = GroupMap::new();
map.insert(built.name, built);
self.kind = ParentType::Group(map);
}
self
}
pub fn command(&mut self, fun: FnPointer<Command<D, T, E>>) -> &mut Self {
let command = fun();
if let ParentType::Simple(map) = &mut self.kind {
map.insert(command.name, command);
} else {
let mut map = CommandMap::new();
map.insert(command.name, command);
self.kind = ParentType::Simple(map);
}
self
}
pub fn build(self) -> GroupParent<D, T, E> {
assert!(self.name.is_some() && self.description.is_some());
GroupParent {
name: self.name.unwrap(),
description: self.description.unwrap(),
kind: self.kind,
required_permissions: self.required_permissions,
}
}
}
pub struct CommandGroupBuilder<D, T, E> {
name: Option<&'static str>,
description: Option<&'static str>,
subcommands: CommandMap<D, T, E>,
}
impl<D, T, E> CommandGroupBuilder<D, T, E> {
pub fn name(&mut self, name: &'static str) -> &mut Self {
self.name = Some(name);
self
}
pub fn description(&mut self, description: &'static str) -> &mut Self {
self.description = Some(description);
self
}
pub fn command(&mut self, fun: FnPointer<Command<D, T, E>>) -> &mut Self {
let command = fun();
self.subcommands.insert(command.name, command);
self
}
pub(crate) fn build(self) -> CommandGroup<D, T, E> {
assert!(self.name.is_some() && self.description.is_some());
CommandGroup {
name: self.name.unwrap(),
description: self.description.unwrap(),
subcommands: self.subcommands,
}
}
pub(crate) fn new() -> Self {
Self {
name: None,
description: None,
subcommands: Default::default(),
}
}
}