twilight_model/application/command/option.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
use crate::channel::ChannelType;
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use std::{cmp::Eq, collections::HashMap};
/// Option for a [`Command`].
///
/// Fields not applicable to the command option's [`CommandOptionType`] should
/// be set to [`None`].
///
/// Fields' default values may be used by setting them to [`None`].
///
/// Choices, descriptions and names may be localized in any [available locale],
/// see [Discord Docs/Localization].
///
/// [available locale]: https://discord.com/developers/docs/reference#locales
/// [`Command`]: super::Command
/// [Discord Docs/Localization]: https://discord.com/developers/docs/interactions/application-commands#localization
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct CommandOption {
/// Whether the command supports autocomplete.
///
/// Applicable for options of type [`Integer`], [`Number`], and [`String`].
///
/// Defaults to `false`.
///
/// **Note**: may not be set to `true` if `choices` are set.
///
/// [`Integer`]: CommandOptionType::Integer
/// [`Number`]: CommandOptionType::Number
/// [`String`]: CommandOptionType::String
#[serde(skip_serializing_if = "Option::is_none")]
pub autocomplete: Option<bool>,
/// List of possible channel types users can select from.
///
/// Applicable for options of type [`Channel`].
///
/// Defaults to any channel type.
///
/// [`Channel`]: CommandOptionType::Channel
#[serde(skip_serializing_if = "Option::is_none")]
pub channel_types: Option<Vec<ChannelType>>,
/// List of predetermined choices users can select from.
///
/// Applicable for options of type [`Integer`], [`Number`], and [`String`].
///
/// Defaults to no choices; users may input a value of their choice.
///
/// Must be at most 25 options.
///
/// **Note**: all choices must be of the same type.
///
/// [`Integer`]: CommandOptionType::Integer
/// [`Number`]: CommandOptionType::Number
/// [`String`]: CommandOptionType::String
#[serde(skip_serializing_if = "Option::is_none")]
pub choices: Option<Vec<CommandOptionChoice>>,
/// Description of the option. Must be 100 characters or less.
pub description: String,
/// Localization dictionary for the [`description`] field.
///
/// Defaults to no localizations.
///
/// Keys must be valid locales and values must be 100 characters or less.
///
/// [`description`]: Self::description
#[serde(skip_serializing_if = "Option::is_none")]
pub description_localizations: Option<HashMap<String, String>>,
/// Type of option.
#[serde(rename = "type")]
pub kind: CommandOptionType,
/// Maximum allowed value length.
///
/// Applicable for options of type [`String`].
///
/// Defaults to `6000`.
///
/// Must be at least `1` and at most `6000`.
///
/// [`String`]: CommandOptionType::String
#[serde(skip_serializing_if = "Option::is_none")]
pub max_length: Option<u16>,
/// Maximum allowed value.
///
/// Applicable for options of type [`Integer`] and [`Number`].
///
/// Defaults to no maximum.
///
/// [`Integer`]: CommandOptionType::Integer
/// [`Number`]: CommandOptionType::Number
#[serde(skip_serializing_if = "Option::is_none")]
pub max_value: Option<CommandOptionValue>,
/// Minimum allowed value length.
///
/// Applicable for options of type [`String`].
///
/// Defaults to `0`.
///
/// Must be at most `6000`.
///
/// [`String`]: CommandOptionType::String
#[serde(skip_serializing_if = "Option::is_none")]
pub min_length: Option<u16>,
/// Minimum allowed value.
///
/// Applicable for options of type [`Integer`] and [`Number`].
///
/// Defaults to no minimum.
///
/// [`Integer`]: CommandOptionType::Integer
/// [`Number`]: CommandOptionType::Number
#[serde(skip_serializing_if = "Option::is_none")]
pub min_value: Option<CommandOptionValue>,
/// Name of the option. Must be 32 characters or less.
pub name: String,
/// Localization dictionary for the [`name`] field.
///
/// Defaults to no localizations.
///
/// Keys must be valid locales and values must be 32 characters or less.
///
/// [`name`]: Self::name
#[serde(skip_serializing_if = "Option::is_none")]
pub name_localizations: Option<HashMap<String, String>>,
/// Nested options.
///
/// Applicable for options of type [`SubCommand`] and [`SubCommandGroup`].
///
/// Defaults to no options.
///
/// **Note**: at least one option is required and [`SubCommandGroup`] may
/// only contain [`SubCommand`]s.
///
/// See [Discord Docs/Subcommands and Subcommand Groups].
///
/// [Discord Docs/Subcommands and Subcommand Groups]: https://discord.com/developers/docs/interactions/application-commands#subcommands-and-subcommand-groups
/// [`SubCommand`]: CommandOptionType::SubCommand
/// [`SubCommandGroup`]: CommandOptionType::SubCommandGroup
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<Vec<CommandOption>>,
/// Whether the option is required.
///
/// Applicable for all options except those of type [`SubCommand`] and
/// [`SubCommandGroup`].
///
/// Defaults to `false`.
///
/// [`SubCommand`]: CommandOptionType::SubCommand
/// [`SubCommandGroup`]: CommandOptionType::SubCommandGroup
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
}
/// A predetermined choice users can select.
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct CommandOptionChoice {
/// Name of the choice. Must be 100 characters or less.
pub name: String,
/// Localization dictionary for the [`name`] field.
///
/// Defaults to no localizations.
///
/// Keys must be valid locales and values must be 100 characters or less.
///
/// See [`CommandOption`]'s documentation for more info.
///
/// [`name`]: Self::name
#[serde(skip_serializing_if = "Option::is_none")]
pub name_localizations: Option<HashMap<String, String>>,
/// Value of the choice.
pub value: CommandOptionChoiceValue,
}
/// Value of a [`CommandOptionChoice`].
///
/// Note that the right variant must be selected based on the
/// [`CommandOption`]'s [`CommandOptionType`].
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum CommandOptionChoiceValue {
/// String choice. Must be 100 characters or less.
String(String),
/// Integer choice.
Integer(i64),
/// Number choice.
Number(f64),
}
/// Type used in the `max_value` and `min_value` [`CommandOption`] field.
///
/// Note that the right variant must be selected based on the
/// [`CommandOption`]'s [`CommandOptionType`].
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum CommandOptionValue {
/// Integer type.
Integer(i64),
/// Number type.
Number(f64),
}
/// Type of a [`CommandOption`].
#[derive(Clone, Copy, Debug, Deserialize_repr, Eq, Hash, PartialEq, Serialize_repr)]
#[non_exhaustive]
#[repr(u8)]
pub enum CommandOptionType {
SubCommand = 1,
SubCommandGroup = 2,
String = 3,
Integer = 4,
Boolean = 5,
User = 6,
Channel = 7,
Role = 8,
Mentionable = 9,
Number = 10,
Attachment = 11,
}
impl CommandOptionType {
pub const fn kind(self) -> &'static str {
match self {
CommandOptionType::SubCommand => "SubCommand",
CommandOptionType::SubCommandGroup => "SubCommandGroup",
CommandOptionType::String => "String",
CommandOptionType::Integer => "Integer",
CommandOptionType::Boolean => "Boolean",
CommandOptionType::User => "User",
CommandOptionType::Channel => "Channel",
CommandOptionType::Role => "Role",
CommandOptionType::Mentionable => "Mentionable",
CommandOptionType::Number => "Number",
CommandOptionType::Attachment => "Attachment",
}
}
}