1use serde::Serialize;
4use twilight_model::{
5 application::interaction::InteractionType,
6 channel::{
7 message::{
8 sticker::MessageSticker, Component, Embed, Message, MessageActivity,
9 MessageApplication, MessageCall, MessageFlags, MessageInteraction, MessageReference,
10 MessageSnapshot, MessageType, Reaction, RoleSubscriptionData,
11 },
12 Attachment, ChannelMention,
13 },
14 guild::PartialMember,
15 id::{
16 marker::{
17 ApplicationMarker, ChannelMarker, GuildMarker, InteractionMarker, MessageMarker,
18 RoleMarker, UserMarker, WebhookMarker,
19 },
20 Id,
21 },
22 poll::Poll,
23 util::Timestamp,
24};
25
26use crate::CacheableMessage;
27
28#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
30pub struct CachedMessageInteraction {
31 id: Id<InteractionMarker>,
32 #[serde(rename = "type")]
33 kind: InteractionType,
34 name: String,
35 user_id: Id<UserMarker>,
36}
37
38impl CachedMessageInteraction {
39 pub const fn id(&self) -> Id<InteractionMarker> {
41 self.id
42 }
43
44 pub const fn kind(&self) -> InteractionType {
46 self.kind
47 }
48
49 pub fn name(&self) -> &str {
51 &self.name
52 }
53
54 pub const fn user_id(&self) -> Id<UserMarker> {
56 self.user_id
57 }
58
59 #[allow(clippy::missing_const_for_fn)]
61 pub(crate) fn from_model(message_interaction: MessageInteraction) -> Self {
62 let MessageInteraction {
66 id,
67 kind,
68 member: _,
69 name,
70 user,
71 } = message_interaction;
72
73 Self {
74 id,
75 kind,
76 name,
77 user_id: user.id,
78 }
79 }
80}
81
82impl PartialEq<MessageInteraction> for CachedMessageInteraction {
83 fn eq(&self, other: &MessageInteraction) -> bool {
84 self.id == other.id
85 && self.kind == other.kind
86 && self.name == other.name
87 && self.user_id == other.user.id
88 }
89}
90
91#[derive(Clone, Debug, PartialEq, Serialize)]
95pub struct CachedMessage {
96 activity: Option<MessageActivity>,
97 application: Option<MessageApplication>,
98 application_id: Option<Id<ApplicationMarker>>,
99 pub(crate) attachments: Vec<Attachment>,
100 author: Id<UserMarker>,
101 pub(crate) call: Option<MessageCall>,
102 channel_id: Id<ChannelMarker>,
103 components: Vec<Component>,
104 pub(crate) content: String,
105 pub(crate) edited_timestamp: Option<Timestamp>,
106 pub(crate) embeds: Vec<Embed>,
107 flags: Option<MessageFlags>,
108 guild_id: Option<Id<GuildMarker>>,
109 id: Id<MessageMarker>,
110 interaction: Option<CachedMessageInteraction>,
111 kind: MessageType,
112 member: Option<PartialMember>,
113 mention_channels: Vec<ChannelMention>,
114 pub(crate) mention_everyone: bool,
115 pub(crate) mention_roles: Vec<Id<RoleMarker>>,
116 pub(crate) mentions: Vec<Id<UserMarker>>,
117 pub(crate) message_snapshots: Vec<MessageSnapshot>,
118 pub(crate) pinned: bool,
119 pub(crate) poll: Option<Poll>,
120 pub(crate) reactions: Vec<Reaction>,
121 reference: Option<MessageReference>,
122 role_subscription_data: Option<RoleSubscriptionData>,
123 sticker_items: Vec<MessageSticker>,
124 thread_id: Option<Id<ChannelMarker>>,
125 pub(crate) timestamp: Timestamp,
126 pub(crate) tts: bool,
127 webhook_id: Option<Id<WebhookMarker>>,
128}
129
130impl CachedMessage {
131 pub const fn activity(&self) -> Option<&MessageActivity> {
133 self.activity.as_ref()
134 }
135
136 pub const fn application(&self) -> Option<&MessageApplication> {
138 self.application.as_ref()
139 }
140
141 pub const fn application_id(&self) -> Option<Id<ApplicationMarker>> {
145 self.application_id
146 }
147
148 pub fn attachments(&self) -> &[Attachment] {
155 &self.attachments
156 }
157
158 pub const fn author(&self) -> Id<UserMarker> {
162 self.author
163 }
164
165 pub const fn channel_id(&self) -> Id<ChannelMarker> {
167 self.channel_id
168 }
169
170 pub fn components(&self) -> &[Component] {
177 &self.components
178 }
179
180 pub fn content(&self) -> &str {
187 &self.content
188 }
189
190 pub const fn edited_timestamp(&self) -> Option<Timestamp> {
192 self.edited_timestamp
193 }
194
195 pub fn embeds(&self) -> &[Embed] {
202 &self.embeds
203 }
204
205 pub const fn flags(&self) -> Option<MessageFlags> {
207 self.flags
208 }
209
210 pub const fn guild_id(&self) -> Option<Id<GuildMarker>> {
212 self.guild_id
213 }
214
215 pub const fn id(&self) -> Id<MessageMarker> {
217 self.id
218 }
219
220 pub const fn interaction(&self) -> Option<&CachedMessageInteraction> {
222 self.interaction.as_ref()
223 }
224
225 pub const fn kind(&self) -> MessageType {
227 self.kind
228 }
229
230 pub const fn member(&self) -> Option<&PartialMember> {
232 self.member.as_ref()
233 }
234
235 pub fn mention_channels(&self) -> &[ChannelMention] {
237 &self.mention_channels
238 }
239
240 pub const fn mention_everyone(&self) -> bool {
242 self.mention_everyone
243 }
244
245 pub fn mention_roles(&self) -> &[Id<RoleMarker>] {
247 &self.mention_roles
248 }
249
250 pub fn mentions(&self) -> &[Id<UserMarker>] {
252 &self.mentions
253 }
254
255 pub const fn pinned(&self) -> bool {
257 self.pinned
258 }
259
260 pub fn reactions(&self) -> &[Reaction] {
262 &self.reactions
263 }
264
265 pub const fn reference(&self) -> Option<&MessageReference> {
267 self.reference.as_ref()
268 }
269
270 pub const fn role_subscription_data(&self) -> Option<&RoleSubscriptionData> {
273 self.role_subscription_data.as_ref()
274 }
275
276 pub fn sticker_items(&self) -> &[MessageSticker] {
278 &self.sticker_items
279 }
280
281 pub const fn thread_id(&self) -> Option<Id<ChannelMarker>> {
283 self.thread_id
284 }
285
286 pub const fn timestamp(&self) -> Timestamp {
288 self.timestamp
289 }
290
291 pub const fn tts(&self) -> bool {
293 self.tts
294 }
295
296 pub const fn webhook_id(&self) -> Option<Id<WebhookMarker>> {
298 self.webhook_id
299 }
300}
301
302impl From<Message> for CachedMessage {
303 #[allow(deprecated)]
304 fn from(message: Message) -> Self {
305 let Message {
306 activity,
307 application,
308 application_id,
309 attachments,
310 author,
311 call,
312 channel_id,
313 components,
314 content,
315 edited_timestamp,
316 embeds,
317 flags,
318 guild_id,
319 id,
320 interaction,
321 interaction_metadata: _,
322 kind,
323 member,
324 mention_channels,
325 mention_everyone,
326 mention_roles,
327 mentions,
328 message_snapshots,
329 pinned,
330 poll,
331 reactions,
332 reference,
333 referenced_message: _,
334 role_subscription_data,
335 sticker_items,
336 timestamp,
337 thread,
338 tts,
339 webhook_id,
340 } = message;
341
342 Self {
343 id,
344 activity,
345 application,
346 application_id,
347 attachments,
348 author: author.id,
349 call,
350 channel_id,
351 components,
352 content,
353 edited_timestamp,
354 embeds,
355 flags,
356 guild_id,
357 interaction: interaction.map(CachedMessageInteraction::from_model),
358 kind,
359 member,
360 mention_channels,
361 mention_everyone,
362 mention_roles,
363 mentions: mentions.into_iter().map(|mention| mention.id).collect(),
364 message_snapshots,
365 pinned,
366 poll,
367 reactions,
368 reference,
369 role_subscription_data,
370 sticker_items,
371 thread_id: thread.map(|thread| thread.id),
372 timestamp,
373 tts,
374 webhook_id,
375 }
376 }
377}
378
379impl PartialEq<Message> for CachedMessage {
380 #[allow(deprecated)]
381 fn eq(&self, other: &Message) -> bool {
382 self.id == other.id
383 && self.activity == other.activity
384 && self.application == other.application
385 && self.application_id == other.application_id
386 && self.attachments == other.attachments
387 && self.author == other.author.id
388 && self.call == other.call
389 && self.channel_id == other.channel_id
390 && self.components == other.components
391 && self.content == other.content
392 && self.edited_timestamp == other.edited_timestamp
393 && self.embeds == other.embeds
394 && self.flags == other.flags
395 && self.guild_id == other.guild_id
396 && self
397 .interaction
398 .as_ref()
399 .map_or(other.interaction.is_none(), |interaction| {
400 other
401 .interaction
402 .as_ref()
403 .is_some_and(|other_interaction| interaction == other_interaction)
404 })
405 && self.kind == other.kind
406 && self.member == other.member
407 && self.mention_channels == other.mention_channels
408 && self.mention_everyone == other.mention_everyone
409 && self.mention_roles == other.mention_roles
410 && self.mentions.len() == other.mentions.len()
411 && self
412 .mentions
413 .iter()
414 .zip(other.mentions.iter())
415 .all(|(user_id, mention)| user_id == &mention.id)
416 && self.pinned == other.pinned
417 && self.reactions == other.reactions
418 && self.reference == other.reference
419 && self.role_subscription_data == other.role_subscription_data
420 && self.sticker_items == other.sticker_items
421 && self.thread_id == other.thread.as_ref().map(|thread| thread.id)
422 && self.timestamp == other.timestamp
423 && self.tts == other.tts
424 && self.webhook_id == other.webhook_id
425 }
426}
427
428impl CacheableMessage for CachedMessage {
429 fn reactions(&self) -> &[Reaction] {
430 &self.reactions
431 }
432
433 fn reactions_mut(&mut self) -> &mut [Reaction] {
434 &mut self.reactions
435 }
436
437 fn retain_reactions(&mut self, f: impl FnMut(&Reaction) -> bool) {
438 self.reactions.retain(f);
439 }
440
441 fn clear_reactions(&mut self) {
442 self.reactions.clear();
443 }
444
445 fn add_reaction(&mut self, reaction: Reaction) {
446 self.reactions.push(reaction);
447 }
448
449 fn remove_reaction(&mut self, idx: usize) {
450 self.reactions.remove(idx);
451 }
452}
453
454#[cfg(test)]
455mod tests {
456 use super::{CachedMessage, CachedMessageInteraction};
457 use serde::Serialize;
458 use static_assertions::{assert_fields, assert_impl_all};
459 use std::fmt::Debug;
460 use twilight_model::channel::message::Message;
461
462 assert_fields!(
463 CachedMessage: activity,
464 application,
465 application_id,
466 attachments,
467 author,
468 channel_id,
469 components,
470 content,
471 edited_timestamp,
472 embeds,
473 flags,
474 guild_id,
475 id,
476 interaction,
477 kind,
478 member,
479 mention_channels,
480 mention_everyone,
481 mention_roles,
482 mentions,
483 pinned,
484 reactions,
485 reference,
486 sticker_items,
487 thread_id,
488 timestamp,
489 tts,
490 webhook_id
491 );
492 assert_impl_all!(
493 CachedMessage: Clone,
494 Debug,
495 From<Message>,
496 PartialEq,
497 Send,
498 Serialize,
499 Sync,
500 );
501 assert_fields!(CachedMessageInteraction: id, kind, name, user_id);
502 assert_impl_all!(
503 CachedMessageInteraction: Clone,
504 Debug,
505 Eq,
506 PartialEq,
507 Send,
508 Serialize,
509 Sync,
510 );
511}