twilight_model/channel/message/component/
kind.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::{Display, Formatter, Result as FmtResult};
3
4/// Type of [`Component`].
5///
6/// [`Component`]: super::Component
7#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
8#[non_exhaustive]
9#[serde(from = "u8", into = "u8")]
10pub enum ComponentType {
11    /// Component is an [`ActionRow`].
12    ///
13    /// [`ActionRow`]: super::ActionRow
14    ActionRow,
15    /// Component is an [`Button`].
16    ///
17    /// [`Button`]: super::Button
18    Button,
19    /// Component is a [`SelectMenu`] with custom string options.
20    ///
21    /// [`SelectMenu`]: super::SelectMenu
22    TextSelectMenu,
23    /// Component is an [`TextInput`].
24    ///
25    /// [`TextInput`]: super::TextInput
26    TextInput,
27    /// Component is a [`SelectMenu`] for users.
28    ///
29    /// [`SelectMenu`]: super::SelectMenu
30    UserSelectMenu,
31    /// Component is a [`SelectMenu`] for roles.
32    ///
33    /// [`SelectMenu`]: super::SelectMenu
34    RoleSelectMenu,
35    /// Component is a [`SelectMenu`] for mentionables.
36    ///
37    /// [`SelectMenu`]: super::SelectMenu
38    MentionableSelectMenu,
39    /// Component is a [`SelectMenu`] for channels.
40    ///
41    /// [`SelectMenu`]: super::SelectMenu
42    ChannelSelectMenu,
43    /// Component is a [`Container`] to display text alongside an accessory component.
44    ///
45    /// [`Container`]: super::Container
46    Section,
47    /// Component is a [`TextDisplay`] containing markdown text.
48    ///
49    /// [`TextDisplay`]: super::TextDisplay
50    TextDisplay,
51    /// Component is a [`Thumbnail`] that can be used as an accessory.
52    ///
53    /// [`Thumbnail`]: super::Thumbnail
54    Thumbnail,
55    /// Component is a [`MediaGallery`] that displays images and other media.
56    ///
57    /// [`MediaGallery`]: super::MediaGallery
58    MediaGallery,
59    /// Component is a [`FileDisplay`] that displays an attached file.
60    ///
61    /// [`FileDisplay`]: super::FileDisplay
62    File,
63    /// Component is a [`Separator`] that adds vertical padding between other components.
64    ///
65    /// [`Separator`]: super::Separator
66    Separator,
67    /// Component is a [`Container`] that visually groups a set of components.
68    ///
69    /// [`Container`]: super::Container
70    Container,
71    /// Component is a [`Label`] that provides a label and an optional description
72    /// for modal components.
73    ///
74    /// [`Label`]: super::Label
75    Label,
76    /// Component is a [`FileUpload`] that allows uploading files in modals.
77    ///
78    /// [`FileUpload`]: super::FileUpload
79    FileUpload,
80    /// Variant value is unknown to the library.
81    Unknown(u8),
82}
83
84impl From<u8> for ComponentType {
85    fn from(value: u8) -> Self {
86        match value {
87            1 => ComponentType::ActionRow,
88            2 => ComponentType::Button,
89            3 => ComponentType::TextSelectMenu,
90            4 => ComponentType::TextInput,
91            5 => ComponentType::UserSelectMenu,
92            6 => ComponentType::RoleSelectMenu,
93            7 => ComponentType::MentionableSelectMenu,
94            8 => ComponentType::ChannelSelectMenu,
95            9 => ComponentType::Section,
96            10 => ComponentType::TextDisplay,
97            11 => ComponentType::Thumbnail,
98            12 => ComponentType::MediaGallery,
99            13 => ComponentType::File,
100            14 => ComponentType::Separator,
101            17 => ComponentType::Container,
102            18 => ComponentType::Label,
103            19 => ComponentType::FileUpload,
104            unknown => ComponentType::Unknown(unknown),
105        }
106    }
107}
108
109impl From<ComponentType> for u8 {
110    fn from(value: ComponentType) -> Self {
111        match value {
112            ComponentType::ActionRow => 1,
113            ComponentType::Button => 2,
114            ComponentType::TextSelectMenu => 3,
115            ComponentType::TextInput => 4,
116            ComponentType::UserSelectMenu => 5,
117            ComponentType::RoleSelectMenu => 6,
118            ComponentType::MentionableSelectMenu => 7,
119            ComponentType::ChannelSelectMenu => 8,
120            ComponentType::Section => 9,
121            ComponentType::TextDisplay => 10,
122            ComponentType::Thumbnail => 11,
123            ComponentType::MediaGallery => 12,
124            ComponentType::File => 13,
125            ComponentType::Separator => 14,
126            ComponentType::Container => 17,
127            ComponentType::Label => 18,
128            ComponentType::FileUpload => 19,
129            ComponentType::Unknown(unknown) => unknown,
130        }
131    }
132}
133
134impl ComponentType {
135    /// Name of the component type.
136    ///
137    /// Variants have a name equivalent to the variant name itself.
138    ///
139    /// # Examples
140    ///
141    /// Check the [`ActionRow`] variant's name:
142    ///
143    /// ```
144    /// use twilight_model::channel::message::component::ComponentType;
145    ///
146    /// assert_eq!("ActionRow", ComponentType::ActionRow.name());
147    /// ```
148    ///
149    /// [`ActionRow`]: Self::ActionRow
150    pub const fn name(self) -> &'static str {
151        match self {
152            ComponentType::ActionRow => "ActionRow",
153            ComponentType::Button => "Button",
154            ComponentType::TextSelectMenu
155            | ComponentType::UserSelectMenu
156            | ComponentType::RoleSelectMenu
157            | ComponentType::MentionableSelectMenu
158            | ComponentType::ChannelSelectMenu => "SelectMenu",
159            ComponentType::TextInput => "TextInput",
160            ComponentType::Section => "Section",
161            ComponentType::TextDisplay => "TextDisplay",
162            ComponentType::Thumbnail => "Thumbnail",
163            ComponentType::MediaGallery => "MediaGallery",
164            ComponentType::File => "File",
165            ComponentType::Separator => "Separator",
166            ComponentType::Container => "Container",
167            ComponentType::Label => "Label",
168            ComponentType::FileUpload => "FileUpload",
169            ComponentType::Unknown(_) => "Unknown",
170        }
171    }
172}
173
174impl Display for ComponentType {
175    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
176        f.write_str(self.name())
177    }
178}
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183    use serde_test::Token;
184    use static_assertions::assert_impl_all;
185    use std::{fmt::Debug, hash::Hash};
186
187    assert_impl_all!(
188        ComponentType: Clone,
189        Copy,
190        Debug,
191        Deserialize<'static>,
192        Eq,
193        Hash,
194        PartialEq,
195        Send,
196        Serialize,
197        Sync
198    );
199
200    #[test]
201    fn variants() {
202        serde_test::assert_tokens(&ComponentType::ActionRow, &[Token::U8(1)]);
203        serde_test::assert_tokens(&ComponentType::Button, &[Token::U8(2)]);
204        serde_test::assert_tokens(&ComponentType::TextSelectMenu, &[Token::U8(3)]);
205        serde_test::assert_tokens(&ComponentType::TextInput, &[Token::U8(4)]);
206        serde_test::assert_tokens(&ComponentType::UserSelectMenu, &[Token::U8(5)]);
207        serde_test::assert_tokens(&ComponentType::RoleSelectMenu, &[Token::U8(6)]);
208        serde_test::assert_tokens(&ComponentType::MentionableSelectMenu, &[Token::U8(7)]);
209        serde_test::assert_tokens(&ComponentType::ChannelSelectMenu, &[Token::U8(8)]);
210        serde_test::assert_tokens(&ComponentType::Section, &[Token::U8(9)]);
211        serde_test::assert_tokens(&ComponentType::TextDisplay, &[Token::U8(10)]);
212        serde_test::assert_tokens(&ComponentType::Thumbnail, &[Token::U8(11)]);
213        serde_test::assert_tokens(&ComponentType::MediaGallery, &[Token::U8(12)]);
214        serde_test::assert_tokens(&ComponentType::File, &[Token::U8(13)]);
215        serde_test::assert_tokens(&ComponentType::Separator, &[Token::U8(14)]);
216        serde_test::assert_tokens(&ComponentType::Container, &[Token::U8(17)]);
217        serde_test::assert_tokens(&ComponentType::Label, &[Token::U8(18)]);
218        serde_test::assert_tokens(&ComponentType::Unknown(99), &[Token::U8(99)]);
219    }
220
221    #[test]
222    fn names() {
223        assert_eq!("ActionRow", ComponentType::ActionRow.name());
224        assert_eq!("Button", ComponentType::Button.name());
225        assert_eq!("SelectMenu", ComponentType::TextSelectMenu.name());
226        assert_eq!("SelectMenu", ComponentType::UserSelectMenu.name());
227        assert_eq!("SelectMenu", ComponentType::RoleSelectMenu.name());
228        assert_eq!("SelectMenu", ComponentType::MentionableSelectMenu.name());
229        assert_eq!("SelectMenu", ComponentType::ChannelSelectMenu.name());
230        assert_eq!("TextInput", ComponentType::TextInput.name());
231        assert_eq!("Section", ComponentType::Section.name());
232        assert_eq!("TextDisplay", ComponentType::TextDisplay.name());
233        assert_eq!("Thumbnail", ComponentType::Thumbnail.name());
234        assert_eq!("MediaGallery", ComponentType::MediaGallery.name());
235        assert_eq!("File", ComponentType::File.name());
236        assert_eq!("Separator", ComponentType::Separator.name());
237        assert_eq!("Container", ComponentType::Container.name());
238        assert_eq!("Label", ComponentType::Label.name());
239        assert_eq!("Unknown", ComponentType::Unknown(99).name());
240    }
241}