twilight_cache_inmemory/event/
emoji.rs1use crate::{config::ResourceType, CacheableModels, GuildResource, InMemoryCache, UpdateCache};
2use std::borrow::Cow;
3use twilight_model::{
4 gateway::payload::incoming::GuildEmojisUpdate,
5 guild::Emoji,
6 id::{marker::GuildMarker, Id},
7};
8
9impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {
10 pub(crate) fn cache_emojis(&self, guild_id: Id<GuildMarker>, emojis: Vec<Emoji>) {
11 if let Some(mut guild_emojis) = self.guild_emojis.get_mut(&guild_id) {
12 let incoming: Vec<_> = emojis.iter().map(|e| e.id).collect();
13
14 let removal_filter: Vec<_> = guild_emojis
15 .iter()
16 .copied()
17 .filter(|e| !incoming.contains(e))
18 .collect();
19
20 for to_remove in &removal_filter {
21 guild_emojis.remove(to_remove);
22 }
23
24 for to_remove in &removal_filter {
25 self.emojis.remove(to_remove);
26 }
27 }
28
29 for emoji in emojis {
30 self.cache_emoji(guild_id, emoji);
31 }
32 }
33
34 pub(crate) fn cache_emoji(&self, guild_id: Id<GuildMarker>, emoji: Emoji) {
35 if let Some(cached_emoji) = self.emojis.get(&emoji.id) {
36 if cached_emoji.value == emoji {
37 return;
38 }
39 }
40
41 if let Some(user) = emoji.user.as_ref() {
42 self.cache_user(Cow::Borrowed(user), Some(guild_id));
43 }
44
45 let emoji_id = emoji.id;
46 let cached = CacheModels::Emoji::from(emoji);
47
48 self.emojis.insert(
49 emoji_id,
50 GuildResource {
51 guild_id,
52 value: cached,
53 },
54 );
55
56 self.guild_emojis
57 .entry(guild_id)
58 .or_default()
59 .insert(emoji_id);
60 }
61}
62
63impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for GuildEmojisUpdate {
64 fn update(&self, cache: &InMemoryCache<CacheModels>) {
65 if !cache.wants(ResourceType::EMOJI) {
66 return;
67 }
68
69 cache.cache_emojis(self.guild_id, self.emojis.clone());
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use crate::{test, DefaultInMemoryCache};
76 use twilight_model::{
77 gateway::payload::incoming::GuildEmojisUpdate,
78 id::{marker::EmojiMarker, Id},
79 user::User,
80 };
81
82 #[test]
83 fn cache_emoji() {
84 fn user_mod(id: Id<EmojiMarker>) -> Option<User> {
86 if id.get() % 2 == 0 {
87 Some(test::user(Id::new(1)))
89 } else {
90 None
91 }
92 }
93
94 let cache = DefaultInMemoryCache::new();
95
96 {
98 let guild_1_emoji_ids = (1..=10).map(Id::new).collect::<Vec<_>>();
99 let guild_1_emoji = guild_1_emoji_ids
100 .iter()
101 .copied()
102 .map(|id| test::emoji(id, user_mod(id)))
103 .collect::<Vec<_>>();
104
105 for emoji in guild_1_emoji {
106 cache.cache_emoji(Id::new(1), emoji);
107 }
108
109 for id in guild_1_emoji_ids.iter().copied() {
110 let global_emoji = cache.emoji(id);
111 assert!(global_emoji.is_some());
112 }
113
114 let guild_emojis = cache.guild_emojis(Id::new(1));
117 assert!(guild_emojis.is_some());
118 let guild_emojis = guild_emojis.unwrap();
119
120 assert_eq!(guild_1_emoji_ids.len(), guild_emojis.len());
121 assert!(guild_1_emoji_ids.iter().all(|id| guild_emojis.contains(id)));
122 }
123
124 {
126 let guild_2_emoji_ids = (11..=20).map(Id::new).collect::<Vec<_>>();
127 let guild_2_emojis = guild_2_emoji_ids
128 .iter()
129 .copied()
130 .map(|id| test::emoji(id, user_mod(id)))
131 .collect::<Vec<_>>();
132 cache.cache_emojis(Id::new(2), guild_2_emojis);
133
134 for id in guild_2_emoji_ids.iter().copied() {
135 let global_emoji = cache.emoji(id);
136 assert!(global_emoji.is_some());
137 }
138
139 let guild_emojis = cache.guild_emojis(Id::new(2));
140
141 assert!(guild_emojis.is_some());
142 let guild_emojis = guild_emojis.unwrap();
143 assert_eq!(guild_2_emoji_ids.len(), guild_emojis.len());
144 assert!(guild_2_emoji_ids.iter().all(|id| guild_emojis.contains(id)));
145 }
146 }
147
148 #[test]
149 fn emoji_removal() {
150 let cache = DefaultInMemoryCache::new();
151
152 let guild_id = Id::new(1);
153
154 let emote = test::emoji(Id::new(1), None);
155 let emote_2 = test::emoji(Id::new(2), None);
156 let emote_3 = test::emoji(Id::new(3), None);
157
158 cache.cache_emoji(guild_id, emote.clone());
159 cache.cache_emoji(guild_id, emote_2.clone());
160 cache.cache_emoji(guild_id, emote_3.clone());
161
162 cache.update(&GuildEmojisUpdate {
163 emojis: vec![emote.clone(), emote_3.clone()],
164 guild_id,
165 });
166
167 assert_eq!(cache.emojis.len(), 2);
168 assert_eq!(cache.guild_emojis.get(&guild_id).unwrap().len(), 2);
169 assert!(cache.emoji(emote.id).is_some());
170 assert!(cache.emoji(emote_2.id).is_none());
171 assert!(cache.emoji(emote_3.id).is_some());
172
173 cache.update(&GuildEmojisUpdate {
174 emojis: vec![emote.clone()],
175 guild_id,
176 });
177
178 assert_eq!(cache.emojis.len(), 1);
179 assert_eq!(cache.guild_emojis.get(&guild_id).unwrap().len(), 1);
180 assert!(cache.emoji(emote.id).is_some());
181 assert!(cache.emoji(emote_2.id).is_none());
182
183 let emote_4 = test::emoji(Id::new(4), None);
184
185 cache.update(&GuildEmojisUpdate {
186 emojis: vec![emote_4.clone()],
187 guild_id,
188 });
189
190 assert_eq!(cache.emojis.len(), 1);
191 assert_eq!(cache.guild_emojis.get(&guild_id).unwrap().len(), 1);
192 assert!(cache.emoji(emote_4.id).is_some());
193 assert!(cache.emoji(emote.id).is_none());
194
195 cache.update(&GuildEmojisUpdate {
196 emojis: vec![],
197 guild_id,
198 });
199
200 assert!(cache.emojis.is_empty());
201 assert!(cache.guild_emojis.get(&guild_id).unwrap().is_empty());
202 }
203}