twilight_embed_builder/
footer.rs

1//! Create embed footers.
2
3use super::image_source::ImageSource;
4use twilight_model::channel::embed::EmbedFooter;
5
6/// Create an embed footer with a builder.
7///
8/// This can be passed into [`EmbedBuilder::footer`].
9///
10/// [`EmbedBuilder::footer`]: crate::EmbedBuilder::footer
11#[derive(Clone, Debug, Eq, PartialEq)]
12#[must_use = "must be built into an embed footer"]
13pub struct EmbedFooterBuilder(EmbedFooter);
14
15impl EmbedFooterBuilder {
16    /// Create a new default embed footer builder.
17    ///
18    /// Refer to [`EmbedBuilder::FOOTER_TEXT_LENGTH_LIMIT`] for the maximum
19    /// number of UTF-16 code points that can be in a footer's text.
20    ///
21    /// [`EmbedBuilder::FOOTER_TEXT_LENGTH_LIMIT`]: crate::EmbedBuilder::FOOTER_TEXT_LENGTH_LIMIT
22    pub fn new(text: impl Into<String>) -> Self {
23        Self::_new(text.into())
24    }
25
26    const fn _new(text: String) -> Self {
27        Self(EmbedFooter {
28            icon_url: None,
29            proxy_icon_url: None,
30            text,
31        })
32    }
33
34    /// Build into an embed footer.
35    #[allow(clippy::missing_const_for_fn)]
36    #[must_use = "should be used as part of an embed builder"]
37    pub fn build(self) -> EmbedFooter {
38        self.0
39    }
40
41    /// Add a footer icon.
42    ///
43    /// # Examples
44    ///
45    /// Create a footer by Twilight with a URL to an image of its logo:
46    ///
47    /// ```
48    /// use twilight_embed_builder::{EmbedFooterBuilder, ImageSource};
49    ///
50    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
51    /// let icon_url = ImageSource::url("https://raw.githubusercontent.com/twilight-rs/twilight/main/logo.png")?;
52    /// let footer = EmbedFooterBuilder::new("Twilight")
53    ///     .icon_url(icon_url)
54    ///     .build();
55    /// # Ok(()) }
56    /// ```
57    pub fn icon_url(mut self, image_source: ImageSource) -> Self {
58        self.0.icon_url.replace(image_source.0);
59
60        self
61    }
62}
63
64impl From<EmbedFooterBuilder> for EmbedFooter {
65    /// Convert an embed footer builder into an embed footer.
66    ///
67    /// This is equivalent to calling [`EmbedFooterBuilder::build`].
68    fn from(builder: EmbedFooterBuilder) -> Self {
69        builder.build()
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::EmbedFooterBuilder;
76    use crate::{EmbedBuilder, EmbedErrorType, ImageSource};
77    use static_assertions::assert_impl_all;
78    use std::fmt::Debug;
79    use twilight_model::channel::embed::EmbedFooter;
80
81    assert_impl_all!(EmbedFooterBuilder: Clone, Debug, Eq, PartialEq, Send, Sync);
82    assert_impl_all!(EmbedFooter: From<EmbedFooterBuilder>);
83
84    #[test]
85    fn text() {
86        assert!(matches!(
87            EmbedBuilder::new().footer(EmbedFooterBuilder::new("")).build().unwrap_err().kind(),
88            EmbedErrorType::FooterTextEmpty { text }
89            if text.is_empty()
90        ));
91        let too_long_len = EmbedBuilder::FOOTER_TEXT_LENGTH_LIMIT + 1;
92        assert!(matches!(
93            EmbedBuilder::new().footer(EmbedFooterBuilder::new("a".repeat(too_long_len))).build().unwrap_err().kind(),
94            EmbedErrorType::FooterTextTooLong { text }
95            if text.len() == too_long_len
96        ));
97
98        let expected = EmbedFooter {
99            icon_url: None,
100            proxy_icon_url: None,
101            text: "a footer".to_owned(),
102        };
103        let actual = EmbedFooterBuilder::new("a footer").build();
104        assert_eq!(actual, expected);
105    }
106
107    #[test]
108    fn builder() {
109        let expected = EmbedFooter {
110            icon_url: Some("https://example.com/1.png".to_owned()),
111            proxy_icon_url: None,
112            text: "a footer".to_owned(),
113        };
114        let image = ImageSource::url("https://example.com/1.png").unwrap();
115        let actual = EmbedFooterBuilder::new("a footer").icon_url(image).build();
116        assert_eq!(actual, expected);
117    }
118}