use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};
use crate::json::{from_value, JsonMap, Value};
use crate::model::channel::ReactionType;
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum ComponentType {
ActionRow = 1,
Button = 2,
SelectMenu = 3,
InputText = 4,
Unknown = !0,
}
enum_number!(ComponentType {
ActionRow,
Button,
SelectMenu,
InputText
});
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActionRow {
#[serde(rename = "type")]
pub kind: ComponentType,
#[serde(default)]
pub components: Vec<ActionRowComponent>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum ActionRowComponent {
Button(Button),
SelectMenu(SelectMenu),
InputText(InputText),
}
impl<'de> Deserialize<'de> for ActionRowComponent {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let map = JsonMap::deserialize(deserializer)?;
let kind = map
.get("type")
.ok_or_else(|| DeError::custom("expected type"))
.and_then(ComponentType::deserialize)
.map_err(DeError::custom)?;
match kind {
ComponentType::Button => from_value::<Button>(Value::from(map))
.map(ActionRowComponent::Button)
.map_err(DeError::custom),
ComponentType::SelectMenu => from_value::<SelectMenu>(Value::from(map))
.map(ActionRowComponent::SelectMenu)
.map_err(DeError::custom),
ComponentType::InputText => from_value::<InputText>(Value::from(map))
.map(ActionRowComponent::InputText)
.map_err(DeError::custom),
_ => Err(DeError::custom("Unknown component type")),
}
}
}
impl Serialize for ActionRowComponent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Self::Button(c) => Button::serialize(c, serializer),
Self::SelectMenu(c) => SelectMenu::serialize(c, serializer),
Self::InputText(c) => InputText::serialize(c, serializer),
}
}
}
impl From<Button> for ActionRowComponent {
fn from(component: Button) -> Self {
ActionRowComponent::Button(component)
}
}
impl From<SelectMenu> for ActionRowComponent {
fn from(component: SelectMenu) -> Self {
ActionRowComponent::SelectMenu(component)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Button {
#[serde(rename = "type")]
pub kind: ComponentType,
pub style: ButtonStyle,
pub label: Option<String>,
pub emoji: Option<ReactionType>,
pub custom_id: Option<String>,
pub url: Option<String>,
#[serde(default)]
pub disabled: bool,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum ButtonStyle {
Primary = 1,
Secondary = 2,
Success = 3,
Danger = 4,
Link = 5,
Unknown = !0,
}
enum_number!(ButtonStyle {
Primary,
Secondary,
Success,
Danger,
Link
});
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SelectMenu {
#[serde(rename = "type")]
pub kind: ComponentType,
pub placeholder: Option<String>,
pub custom_id: Option<String>,
pub min_values: Option<u64>,
pub max_values: Option<u64>,
#[serde(default)]
pub options: Vec<SelectMenuOption>,
#[serde(default)]
pub values: Vec<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SelectMenuOption {
pub label: String,
pub value: String,
pub description: Option<String>,
pub emoji: Option<ReactionType>,
#[serde(default)]
pub default: bool,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InputText {
#[serde(rename = "type")]
pub kind: ComponentType,
pub custom_id: String,
pub value: String,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InputTextStyle {
Short = 1,
Paragraph = 2,
Unknown = !0,
}
enum_number!(InputTextStyle {
Short,
Paragraph,
Unknown
});