1use serde::Serialize;
4use twilight_model::{
5 application::interaction::InteractionType,
6 channel::{
7 Attachment, ChannelMention,
8 message::{
9 Component, Embed, Message, MessageActivity, MessageApplication, MessageCall,
10 MessageFlags, MessageInteraction, MessageReference, MessageSnapshot, MessageType,
11 Reaction, RoleSubscriptionData, sticker::MessageSticker,
12 },
13 },
14 guild::PartialMember,
15 id::{
16 Id,
17 marker::{
18 ApplicationMarker, ChannelMarker, GuildMarker, InteractionMarker, MessageMarker,
19 RoleMarker, UserMarker, WebhookMarker,
20 },
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 call(&self) -> Option<&MessageCall> {
169 self.call.as_ref()
170 }
171
172 pub const fn channel_id(&self) -> Id<ChannelMarker> {
174 self.channel_id
175 }
176
177 #[allow(clippy::missing_const_for_fn)]
184 pub fn components(&self) -> &[Component] {
185 &self.components
186 }
187
188 #[allow(clippy::missing_const_for_fn)]
195 pub fn content(&self) -> &str {
196 &self.content
197 }
198
199 pub const fn edited_timestamp(&self) -> Option<Timestamp> {
201 self.edited_timestamp
202 }
203
204 #[allow(clippy::missing_const_for_fn)]
211 pub fn embeds(&self) -> &[Embed] {
212 &self.embeds
213 }
214
215 pub const fn flags(&self) -> Option<MessageFlags> {
217 self.flags
218 }
219
220 pub const fn guild_id(&self) -> Option<Id<GuildMarker>> {
222 self.guild_id
223 }
224
225 pub const fn id(&self) -> Id<MessageMarker> {
227 self.id
228 }
229
230 pub const fn interaction(&self) -> Option<&CachedMessageInteraction> {
232 self.interaction.as_ref()
233 }
234
235 pub const fn kind(&self) -> MessageType {
237 self.kind
238 }
239
240 pub const fn member(&self) -> Option<&PartialMember> {
242 self.member.as_ref()
243 }
244
245 #[allow(clippy::missing_const_for_fn)]
247 pub fn mention_channels(&self) -> &[ChannelMention] {
248 &self.mention_channels
249 }
250
251 pub const fn mention_everyone(&self) -> bool {
253 self.mention_everyone
254 }
255
256 #[allow(clippy::missing_const_for_fn)]
258 pub fn mention_roles(&self) -> &[Id<RoleMarker>] {
259 &self.mention_roles
260 }
261
262 #[allow(clippy::missing_const_for_fn)]
264 pub fn mentions(&self) -> &[Id<UserMarker>] {
265 &self.mentions
266 }
267
268 pub fn message_snapshots(&self) -> &[MessageSnapshot] {
272 &self.message_snapshots
273 }
274
275 pub const fn pinned(&self) -> bool {
277 self.pinned
278 }
279
280 #[allow(clippy::missing_const_for_fn)]
282 pub fn reactions(&self) -> &[Reaction] {
283 &self.reactions
284 }
285
286 pub const fn reference(&self) -> Option<&MessageReference> {
288 self.reference.as_ref()
289 }
290
291 pub const fn role_subscription_data(&self) -> Option<&RoleSubscriptionData> {
294 self.role_subscription_data.as_ref()
295 }
296
297 #[allow(clippy::missing_const_for_fn)]
299 pub fn sticker_items(&self) -> &[MessageSticker] {
300 &self.sticker_items
301 }
302
303 pub const fn thread_id(&self) -> Option<Id<ChannelMarker>> {
305 self.thread_id
306 }
307
308 pub const fn timestamp(&self) -> Timestamp {
310 self.timestamp
311 }
312
313 pub const fn tts(&self) -> bool {
315 self.tts
316 }
317
318 pub const fn webhook_id(&self) -> Option<Id<WebhookMarker>> {
320 self.webhook_id
321 }
322}
323
324impl From<Message> for CachedMessage {
325 #[allow(deprecated)]
326 fn from(message: Message) -> Self {
327 let Message {
328 activity,
329 application,
330 application_id,
331 attachments,
332 author,
333 call,
334 channel_id,
335 components,
336 content,
337 edited_timestamp,
338 embeds,
339 flags,
340 guild_id,
341 id,
342 interaction,
343 interaction_metadata: _,
344 kind,
345 member,
346 mention_channels,
347 mention_everyone,
348 mention_roles,
349 mentions,
350 message_snapshots,
351 pinned,
352 poll,
353 reactions,
354 reference,
355 referenced_message: _,
356 role_subscription_data,
357 sticker_items,
358 timestamp,
359 thread,
360 tts,
361 webhook_id,
362 } = message;
363
364 Self {
365 id,
366 activity,
367 application,
368 application_id,
369 attachments,
370 author: author.id,
371 call,
372 channel_id,
373 components,
374 content,
375 edited_timestamp,
376 embeds,
377 flags,
378 guild_id,
379 interaction: interaction.map(CachedMessageInteraction::from_model),
380 kind,
381 member,
382 mention_channels,
383 mention_everyone,
384 mention_roles,
385 mentions: mentions.into_iter().map(|mention| mention.id).collect(),
386 message_snapshots,
387 pinned,
388 poll,
389 reactions,
390 reference,
391 role_subscription_data,
392 sticker_items,
393 thread_id: thread.map(|thread| thread.id),
394 timestamp,
395 tts,
396 webhook_id,
397 }
398 }
399}
400
401impl PartialEq<Message> for CachedMessage {
402 #[allow(deprecated)]
403 fn eq(&self, other: &Message) -> bool {
404 self.id == other.id
405 && self.activity == other.activity
406 && self.application == other.application
407 && self.application_id == other.application_id
408 && self.attachments == other.attachments
409 && self.author == other.author.id
410 && self.call == other.call
411 && self.channel_id == other.channel_id
412 && self.components == other.components
413 && self.content == other.content
414 && self.edited_timestamp == other.edited_timestamp
415 && self.embeds == other.embeds
416 && self.flags == other.flags
417 && self.guild_id == other.guild_id
418 && self
419 .interaction
420 .as_ref()
421 .map_or(other.interaction.is_none(), |interaction| {
422 other
423 .interaction
424 .as_ref()
425 .is_some_and(|other_interaction| interaction == other_interaction)
426 })
427 && self.kind == other.kind
428 && self.member == other.member
429 && self.mention_channels == other.mention_channels
430 && self.mention_everyone == other.mention_everyone
431 && self.mention_roles == other.mention_roles
432 && self.mentions.len() == other.mentions.len()
433 && self
434 .mentions
435 .iter()
436 .zip(other.mentions.iter())
437 .all(|(user_id, mention)| user_id == &mention.id)
438 && self.pinned == other.pinned
439 && self.reactions == other.reactions
440 && self.reference == other.reference
441 && self.role_subscription_data == other.role_subscription_data
442 && self.sticker_items == other.sticker_items
443 && self.thread_id == other.thread.as_ref().map(|thread| thread.id)
444 && self.timestamp == other.timestamp
445 && self.tts == other.tts
446 && self.webhook_id == other.webhook_id
447 }
448}
449
450impl CacheableMessage for CachedMessage {
451 fn reactions(&self) -> &[Reaction] {
452 &self.reactions
453 }
454
455 fn reactions_mut(&mut self) -> &mut [Reaction] {
456 &mut self.reactions
457 }
458
459 fn retain_reactions(&mut self, f: impl FnMut(&Reaction) -> bool) {
460 self.reactions.retain(f);
461 }
462
463 fn clear_reactions(&mut self) {
464 self.reactions.clear();
465 }
466
467 fn add_reaction(&mut self, reaction: Reaction) {
468 self.reactions.push(reaction);
469 }
470
471 fn remove_reaction(&mut self, idx: usize) {
472 self.reactions.remove(idx);
473 }
474}
475
476#[cfg(test)]
477mod tests {
478 use super::{CachedMessage, CachedMessageInteraction};
479 use serde::Serialize;
480 use static_assertions::{assert_fields, assert_impl_all};
481 use std::fmt::Debug;
482 use twilight_model::channel::message::Message;
483
484 assert_fields!(
485 CachedMessage: activity,
486 application,
487 application_id,
488 attachments,
489 author,
490 channel_id,
491 components,
492 content,
493 edited_timestamp,
494 embeds,
495 flags,
496 guild_id,
497 id,
498 interaction,
499 kind,
500 member,
501 mention_channels,
502 mention_everyone,
503 mention_roles,
504 mentions,
505 pinned,
506 reactions,
507 reference,
508 sticker_items,
509 thread_id,
510 timestamp,
511 tts,
512 webhook_id
513 );
514 assert_impl_all!(
515 CachedMessage: Clone,
516 Debug,
517 From<Message>,
518 PartialEq,
519 Send,
520 Serialize,
521 Sync,
522 );
523 assert_fields!(CachedMessageInteraction: id, kind, name, user_id);
524 assert_impl_all!(
525 CachedMessageInteraction: Clone,
526 Debug,
527 Eq,
528 PartialEq,
529 Send,
530 Serialize,
531 Sync,
532 );
533}