use std::{borrow::Cow, collections::HashMap};
use twilight_model::{
application::{
command::{Command, CommandOption, CommandOptionType, CommandType},
interaction::{InteractionChannel, InteractionContextType},
},
channel::Attachment,
guild::{Permissions, Role},
id::{
marker::{AttachmentMarker, ChannelMarker, GenericMarker, RoleMarker, UserMarker},
Id,
},
oauth::ApplicationIntegrationType,
user::User,
};
use super::{internal::CreateOptionData, ResolvedMentionable, ResolvedUser};
pub trait CreateCommand: Sized {
const NAME: &'static str;
fn create_command() -> ApplicationCommandData;
}
impl<T: CreateCommand> CreateCommand for Box<T> {
const NAME: &'static str = T::NAME;
fn create_command() -> ApplicationCommandData {
T::create_command()
}
}
pub trait CreateOption: Sized {
fn create_option(data: CreateOptionData) -> CommandOption;
}
#[derive(Debug, Clone, PartialEq)]
pub struct NameLocalizations {
pub(crate) localizations: HashMap<String, String>,
}
impl NameLocalizations {
pub fn new(
localizations: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
) -> Self {
let localizations = localizations
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
Self { localizations }
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct DescLocalizations {
pub(crate) fallback: String,
pub(crate) localizations: HashMap<String, String>,
}
impl DescLocalizations {
pub fn new(
fallback: impl Into<String>,
localizations: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
) -> Self {
let fallback = fallback.into();
let localizations = localizations
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
Self {
fallback,
localizations,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ApplicationCommandData {
pub name: String,
pub name_localizations: Option<HashMap<String, String>>,
pub description: String,
pub description_localizations: Option<HashMap<String, String>>,
pub options: Vec<CommandOption>,
#[deprecated(note = "use contexts instead")]
pub dm_permission: Option<bool>,
pub default_member_permissions: Option<Permissions>,
pub group: bool,
pub nsfw: Option<bool>,
pub contexts: Option<Vec<InteractionContextType>>,
pub integration_types: Option<Vec<ApplicationIntegrationType>>,
}
impl From<ApplicationCommandData> for Command {
fn from(item: ApplicationCommandData) -> Self {
#[allow(deprecated)]
Command {
application_id: None,
guild_id: None,
name: item.name,
name_localizations: item.name_localizations,
default_member_permissions: item.default_member_permissions,
dm_permission: item.dm_permission,
description: item.description,
description_localizations: item.description_localizations,
id: None,
kind: CommandType::ChatInput,
nsfw: item.nsfw,
options: item.options,
version: Id::new(1),
contexts: item.contexts,
integration_types: item.integration_types,
}
}
}
impl From<ApplicationCommandData> for CommandOption {
fn from(item: ApplicationCommandData) -> Self {
let data = CreateOptionData {
name: item.name,
name_localizations: item.name_localizations,
description: item.description,
description_localizations: item.description_localizations,
required: None,
autocomplete: false,
data: Default::default(),
};
if item.group {
data.builder(CommandOptionType::SubCommandGroup)
.options(item.options)
.build()
} else {
data.builder(CommandOptionType::SubCommand)
.options(item.options)
.build()
}
}
}
impl CreateOption for String {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::String)
}
}
impl CreateOption for Cow<'_, str> {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::String)
}
}
impl CreateOption for i64 {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Integer)
}
}
impl CreateOption for f64 {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Number)
}
}
impl CreateOption for bool {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Boolean)
}
}
impl CreateOption for Id<UserMarker> {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::User)
}
}
impl CreateOption for Id<ChannelMarker> {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Channel)
}
}
impl CreateOption for Id<RoleMarker> {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Role)
}
}
impl CreateOption for Id<GenericMarker> {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Mentionable)
}
}
impl CreateOption for Id<AttachmentMarker> {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Attachment)
}
}
impl CreateOption for Attachment {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Attachment)
}
}
impl CreateOption for User {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::User)
}
}
impl CreateOption for ResolvedUser {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::User)
}
}
impl CreateOption for ResolvedMentionable {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Mentionable)
}
}
impl CreateOption for InteractionChannel {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Channel)
}
}
impl CreateOption for Role {
fn create_option(data: CreateOptionData) -> CommandOption {
data.into_option(CommandOptionType::Role)
}
}