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