twilight_embed_builder/
author.rs

1//! Create embed authors.
2
3use super::image_source::ImageSource;
4use twilight_model::channel::embed::EmbedAuthor;
5
6/// Create an embed author with a builder.
7///
8/// This can be passed into [`EmbedBuilder::author`].
9///
10/// [`EmbedBuilder::author`]: crate::EmbedBuilder::author
11#[derive(Clone, Debug, Eq, PartialEq)]
12#[must_use = "must be built into an embed author"]
13pub struct EmbedAuthorBuilder(EmbedAuthor);
14
15impl EmbedAuthorBuilder {
16    /// Create a new embed author builder.
17    pub const fn new(name: String) -> Self {
18        Self(EmbedAuthor {
19            icon_url: None,
20            name,
21            proxy_icon_url: None,
22            url: None,
23        })
24    }
25
26    /// Build into an embed author.
27    #[allow(clippy::missing_const_for_fn)]
28    #[must_use = "should be used as part of an embed builder"]
29    pub fn build(self) -> EmbedAuthor {
30        self.0
31    }
32
33    /// Add an author icon.
34    pub fn icon_url(mut self, image_source: ImageSource) -> Self {
35        self.0.icon_url.replace(image_source.0);
36
37        self
38    }
39
40    /// The author's name.
41    ///
42    /// Refer to [`EmbedBuilder::AUTHOR_NAME_LENGTH_LIMIT`] for the maximum
43    /// number of UTF-16 code points that can be in an author name.
44    ///
45    /// [`EmbedBuilder::AUTHOR_NAME_LENGTH_LIMIT`]: crate::EmbedBuilder::AUTHOR_NAME_LENGTH_LIMIT
46    pub fn name(self, name: impl Into<String>) -> Self {
47        self._name(name.into())
48    }
49
50    #[allow(clippy::missing_const_for_fn)]
51    fn _name(mut self, name: String) -> Self {
52        self.0.name = name;
53
54        self
55    }
56
57    /// The author's url.
58    pub fn url(self, url: impl Into<String>) -> Self {
59        self._url(url.into())
60    }
61
62    fn _url(mut self, url: String) -> Self {
63        self.0.url.replace(url);
64
65        self
66    }
67}
68
69impl From<EmbedAuthorBuilder> for EmbedAuthor {
70    /// Convert an embed author builder into an embed author.
71    ///
72    /// This is equivalent to calling [`EmbedAuthorBuilder::build`].
73    fn from(builder: EmbedAuthorBuilder) -> Self {
74        builder.build()
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::EmbedAuthorBuilder;
81    use crate::{EmbedBuilder, EmbedErrorType, ImageSource};
82    use static_assertions::assert_impl_all;
83    use std::fmt::Debug;
84    use twilight_model::channel::embed::EmbedAuthor;
85
86    assert_impl_all!(EmbedAuthorBuilder: Clone, Debug, Eq, PartialEq, Send, Sync);
87    assert_impl_all!(EmbedAuthor: From<EmbedAuthorBuilder>);
88
89    #[test]
90    fn name_empty() {
91        let builder = EmbedBuilder::new().author(EmbedAuthorBuilder::new("".to_owned()));
92
93        assert!(matches!(
94            builder.build().unwrap_err().kind(),
95            EmbedErrorType::AuthorNameEmpty { .. }
96        ));
97    }
98
99    #[test]
100    fn name_too_long() {
101        let builder = EmbedBuilder::new().author(EmbedAuthorBuilder::new("a".repeat(256)));
102        assert!(builder.build().is_ok());
103
104        let builder = EmbedBuilder::new().author(EmbedAuthorBuilder::new("a".repeat(257)));
105        assert!(matches!(
106            builder.build().unwrap_err().kind(),
107            EmbedErrorType::AuthorNameTooLong { .. }
108        ));
109    }
110
111    #[test]
112    fn builder() {
113        let expected = EmbedAuthor {
114            icon_url: Some("https://example.com/1.png".to_owned()),
115            name: "an author".to_owned(),
116            proxy_icon_url: None,
117            url: Some("https://example.com".to_owned()),
118        };
119
120        let source = ImageSource::url("https://example.com/1.png").unwrap();
121        let actual = EmbedAuthorBuilder::new("an author".to_owned())
122            .icon_url(source)
123            .url("https://example.com")
124            .build();
125
126        assert_eq!(actual, expected);
127    }
128}