twilight_cache_inmemory/model/
sticker.rs

1use serde::Serialize;
2use twilight_model::{
3    channel::message::{
4        sticker::{StickerFormatType, StickerType},
5        Sticker,
6    },
7    id::{
8        marker::{GuildMarker, StickerMarker, StickerPackMarker, UserMarker},
9        Id,
10    },
11};
12
13use crate::CacheableSticker;
14
15/// Representation of a cached [`Sticker`].
16///
17/// [`Sticker`]: twilight_model::channel::message::sticker::Sticker
18#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
19pub struct CachedSticker {
20    /// Whether the sticker is available.
21    pub(crate) available: bool,
22    /// Description of the sticker.
23    pub(crate) description: String,
24    /// Format type.
25    pub(crate) format_type: StickerFormatType,
26    /// ID of the guild that owns the sticker.
27    pub(crate) guild_id: Option<Id<GuildMarker>>,
28    /// Unique ID of the sticker.
29    pub(crate) id: Id<StickerMarker>,
30    /// Kind of sticker.
31    pub(crate) kind: StickerType,
32    /// Name of the sticker.
33    pub(crate) name: String,
34    /// Unique ID of the pack the sticker is in.
35    pub(crate) pack_id: Option<Id<StickerPackMarker>>,
36    /// Sticker's sort order within a pack.
37    pub(crate) sort_value: Option<u64>,
38    /// CSV list of tags the sticker is assigned to, if any.
39    pub(crate) tags: String,
40    /// ID of the user that uploaded the sticker.
41    pub(crate) user_id: Option<Id<UserMarker>>,
42}
43
44impl CachedSticker {
45    /// Whether the sticker is available.
46    pub const fn available(&self) -> bool {
47        self.available
48    }
49
50    /// Description of the sticker.
51    #[allow(clippy::missing_const_for_fn)]
52    pub fn description(&self) -> &str {
53        &self.description
54    }
55
56    /// Format type.
57    pub const fn format_type(&self) -> StickerFormatType {
58        self.format_type
59    }
60
61    /// ID of the guild that owns the sticker.
62    pub const fn guild_id(&self) -> Option<Id<GuildMarker>> {
63        self.guild_id
64    }
65
66    /// Unique ID of the sticker.
67    pub const fn id(&self) -> Id<StickerMarker> {
68        self.id
69    }
70
71    /// Kind of sticker.
72    pub const fn kind(&self) -> StickerType {
73        self.kind
74    }
75
76    /// Name of the sticker.
77    #[allow(clippy::missing_const_for_fn)]
78    pub fn name(&self) -> &str {
79        &self.name
80    }
81
82    /// Unique ID of the pack the sticker is in.
83    pub const fn pack_id(&self) -> Option<Id<StickerPackMarker>> {
84        self.pack_id
85    }
86
87    /// Sticker's sort order within a pack.
88    pub const fn sort_value(&self) -> Option<u64> {
89        self.sort_value
90    }
91
92    /// CSV list of tags the sticker is assigned to, if any.
93    #[allow(clippy::missing_const_for_fn)]
94    pub fn tags(&self) -> &str {
95        &self.tags
96    }
97
98    /// ID of the user that uploaded the sticker.
99    pub const fn user_id(&self) -> Option<Id<UserMarker>> {
100        self.user_id
101    }
102}
103
104impl From<Sticker> for CachedSticker {
105    fn from(sticker: Sticker) -> Self {
106        let Sticker {
107            available,
108            description,
109            format_type,
110            guild_id,
111            id,
112            kind,
113            name,
114            pack_id,
115            sort_value,
116            tags,
117            user,
118        } = sticker;
119
120        Self {
121            available,
122            description: description.unwrap_or_default(),
123            format_type,
124            guild_id,
125            id,
126            kind,
127            name,
128            pack_id,
129            sort_value,
130            tags,
131            user_id: user.map(|user| user.id),
132        }
133    }
134}
135
136impl PartialEq<Sticker> for CachedSticker {
137    fn eq(&self, other: &Sticker) -> bool {
138        self.available == other.available
139            && self.description.as_str() == other.description.as_ref().map_or("", String::as_str)
140            && self.format_type == other.format_type
141            && self.guild_id == other.guild_id
142            && self.id == other.id
143            && self.kind == other.kind
144            && self.name == other.name
145            && self.pack_id == other.pack_id
146            && self.sort_value == other.sort_value
147            && self.tags == other.tags
148            && self.user_id == other.user.as_ref().map(|user| user.id)
149    }
150}
151
152impl CacheableSticker for CachedSticker {
153    fn id(&self) -> Id<StickerMarker> {
154        self.id
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::CachedSticker;
161    use serde::Serialize;
162    use static_assertions::{assert_fields, assert_impl_all};
163    use std::fmt::Debug;
164    use twilight_model::{
165        channel::message::{
166            sticker::{StickerFormatType, StickerType},
167            Sticker,
168        },
169        id::Id,
170        user::{PremiumType, User, UserFlags},
171        util::{image_hash::ImageHashParseError, ImageHash},
172    };
173
174    assert_fields!(
175        CachedSticker: available,
176        description,
177        format_type,
178        guild_id,
179        id,
180        kind,
181        name,
182        pack_id,
183        sort_value,
184        tags,
185        user_id
186    );
187    assert_impl_all!(
188        CachedSticker: Clone,
189        Debug,
190        Eq,
191        PartialEq,
192        PartialEq<Sticker>,
193        Send,
194        Serialize,
195        Sync
196    );
197
198    #[test]
199    fn eq_sticker() -> Result<(), ImageHashParseError> {
200        let avatar = ImageHash::parse(b"5bf451026c107906b4dccea015320222")?;
201
202        let sticker = Sticker {
203            available: true,
204            description: Some("sticker".into()),
205            format_type: StickerFormatType::Png,
206            guild_id: Some(Id::new(1)),
207            id: Id::new(2),
208            kind: StickerType::Guild,
209            name: "stick".into(),
210            pack_id: Some(Id::new(3)),
211            sort_value: Some(1),
212            tags: "foo,bar,baz".into(),
213            user: Some(User {
214                accent_color: None,
215                avatar: Some(avatar),
216                avatar_decoration: None,
217                avatar_decoration_data: None,
218                banner: None,
219                bot: false,
220                discriminator: 1,
221                email: Some("address@example.com".to_owned()),
222                flags: Some(UserFlags::PREMIUM_EARLY_SUPPORTER | UserFlags::VERIFIED_DEVELOPER),
223                global_name: Some("test".to_owned()),
224                id: Id::new(1),
225                locale: Some("en-us".to_owned()),
226                mfa_enabled: Some(true),
227                name: "test".to_owned(),
228                premium_type: Some(PremiumType::Nitro),
229                public_flags: Some(
230                    UserFlags::PREMIUM_EARLY_SUPPORTER | UserFlags::VERIFIED_DEVELOPER,
231                ),
232                system: Some(true),
233                verified: Some(true),
234            }),
235        };
236
237        let cached = CachedSticker {
238            available: true,
239            description: "sticker".into(),
240            format_type: StickerFormatType::Png,
241            guild_id: Some(Id::new(1)),
242            id: Id::new(2),
243            kind: StickerType::Guild,
244            name: "stick".into(),
245            pack_id: Some(Id::new(3)),
246            sort_value: Some(1),
247            tags: "foo,bar,baz".into(),
248            user_id: Some(Id::new(1)),
249        };
250
251        assert_eq!(cached, sticker);
252
253        Ok(())
254    }
255}