tulpje_cache/models/
message.rs

1use serde::{Deserialize, Serialize};
2use twilight_model::{
3    application::interaction::InteractionType,
4    channel::{
5        Attachment, ChannelMention, Message,
6        message::{
7            Component, Embed, MessageActivity, MessageApplication, MessageCall, MessageFlags,
8            MessageInteraction, MessageReference, MessageSnapshot, MessageSticker, MessageType,
9            Reaction, RoleSubscriptionData,
10        },
11    },
12    guild::PartialMember,
13    id::{
14        Id,
15        marker::{
16            ApplicationMarker, ChannelMarker, GuildMarker, InteractionMarker, MessageMarker,
17            RoleMarker, UserMarker, WebhookMarker,
18        },
19    },
20    poll::Poll,
21    util::Timestamp,
22};
23
24/// Information about the message interaction.
25#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
26pub struct CachedMessageInteraction {
27    pub id: Id<InteractionMarker>,
28    #[serde(rename = "type")]
29    pub kind: InteractionType,
30    pub name: String,
31    pub user_id: Id<UserMarker>,
32}
33
34impl From<MessageInteraction> for CachedMessageInteraction {
35    fn from(message_interaction: MessageInteraction) -> Self {
36        // Reasons for dropping fields:
37        //
38        // - `member`: we have the user's ID from the `user_id` field
39        #[expect(
40            clippy::unneeded_field_pattern,
41            reason = "clearer that we're explicitly skipping those fields"
42        )]
43        let MessageInteraction {
44            id,
45            kind,
46            member: _,
47            name,
48            user,
49        } = message_interaction;
50
51        Self {
52            id,
53            kind,
54            name,
55            user_id: user.id,
56        }
57    }
58}
59
60impl PartialEq<MessageInteraction> for CachedMessageInteraction {
61    fn eq(&self, other: &MessageInteraction) -> bool {
62        self.id == other.id
63            && self.kind == other.kind
64            && self.name == other.name
65            && self.user_id == other.user.id
66    }
67}
68
69#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
70pub struct CachedMessage {
71    pub activity: Option<MessageActivity>,
72    pub application: Option<MessageApplication>,
73    pub application_id: Option<Id<ApplicationMarker>>,
74    pub attachments: Vec<Attachment>,
75    pub author: Id<UserMarker>,
76    pub call: Option<MessageCall>,
77    pub channel_id: Id<ChannelMarker>,
78    pub components: Vec<Component>,
79    pub content: String,
80    pub edited_timestamp: Option<Timestamp>,
81    pub embeds: Vec<Embed>,
82    pub flags: Option<MessageFlags>,
83    pub guild_id: Option<Id<GuildMarker>>,
84    pub id: Id<MessageMarker>,
85    pub interaction: Option<CachedMessageInteraction>,
86    pub kind: MessageType,
87    pub member: Option<PartialMember>,
88    pub mention_channels: Vec<ChannelMention>,
89    pub mention_everyone: bool,
90    pub mention_roles: Vec<Id<RoleMarker>>,
91    pub mentions: Vec<Id<UserMarker>>,
92    pub message_snapshots: Vec<MessageSnapshot>,
93    pub pinned: bool,
94    pub poll: Option<Poll>,
95    pub reactions: Vec<Reaction>,
96    pub reference: Option<MessageReference>,
97    pub role_subscription_data: Option<RoleSubscriptionData>,
98    pub sticker_items: Vec<MessageSticker>,
99    pub thread_id: Option<Id<ChannelMarker>>,
100    pub timestamp: Timestamp,
101    pub tts: bool,
102    pub webhook_id: Option<Id<WebhookMarker>>,
103}
104
105impl From<Message> for CachedMessage {
106    #[expect(deprecated)]
107    fn from(message: Message) -> Self {
108        #[expect(
109            clippy::unneeded_field_pattern,
110            reason = "clearer that we're explicitly skipping those fields"
111        )]
112        let Message {
113            activity,
114            application,
115            application_id,
116            attachments,
117            author,
118            call,
119            channel_id,
120            components,
121            content,
122            edited_timestamp,
123            embeds,
124            flags,
125            guild_id,
126            id,
127            interaction,
128            interaction_metadata: _,
129            kind,
130            member,
131            mention_channels,
132            mention_everyone,
133            mention_roles,
134            mentions,
135            message_snapshots,
136            pinned,
137            poll,
138            reactions,
139            reference,
140            referenced_message: _,
141            role_subscription_data,
142            sticker_items,
143            timestamp,
144            thread,
145            tts,
146            webhook_id,
147        } = message;
148
149        Self {
150            id,
151            activity,
152            application,
153            application_id,
154            attachments,
155            author: author.id,
156            call,
157            channel_id,
158            components,
159            content,
160            edited_timestamp,
161            embeds,
162            flags,
163            guild_id,
164            interaction: interaction.map(CachedMessageInteraction::from),
165            kind,
166            member,
167            mention_channels,
168            mention_everyone,
169            mention_roles,
170            mentions: mentions.into_iter().map(|mention| mention.id).collect(),
171            message_snapshots,
172            pinned,
173            poll,
174            reactions,
175            reference,
176            role_subscription_data,
177            sticker_items,
178            thread_id: thread.map(|thread| thread.id),
179            timestamp,
180            tts,
181            webhook_id,
182        }
183    }
184}
185
186impl PartialEq<Message> for CachedMessage {
187    #[expect(deprecated)]
188    fn eq(&self, other: &Message) -> bool {
189        self.id == other.id
190            && self.activity == other.activity
191            && self.application == other.application
192            && self.application_id == other.application_id
193            && self.attachments == other.attachments
194            && self.author == other.author.id
195            && self.call == other.call
196            && self.channel_id == other.channel_id
197            && self.components == other.components
198            && self.content == other.content
199            && self.edited_timestamp == other.edited_timestamp
200            && self.embeds == other.embeds
201            && self.flags == other.flags
202            && self.guild_id == other.guild_id
203            && self.interaction.as_ref().map_or_else(
204                || other.interaction.is_none(),
205                |interaction| {
206                    other
207                        .interaction
208                        .as_ref()
209                        .is_some_and(|other_interaction| interaction == other_interaction)
210                },
211            )
212            && self.kind == other.kind
213            && self.member == other.member
214            && self.mention_channels == other.mention_channels
215            && self.mention_everyone == other.mention_everyone
216            && self.mention_roles == other.mention_roles
217            && self.mentions.len() == other.mentions.len()
218            && self
219                .mentions
220                .iter()
221                .zip(other.mentions.iter())
222                .all(|(user_id, mention)| user_id == &mention.id)
223            && self.pinned == other.pinned
224            && self.reactions == other.reactions
225            && self.reference == other.reference
226            && self.role_subscription_data == other.role_subscription_data
227            && self.sticker_items == other.sticker_items
228            && self.thread_id == other.thread.as_ref().map(|thread| thread.id)
229            && self.timestamp == other.timestamp
230            && self.tts == other.tts
231            && self.webhook_id == other.webhook_id
232    }
233}