Skip to main content

ruma_events/
enums.rs

1use ruma_common::{
2    EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId, TransactionId, UserId,
3    serde::{JsonCastable, from_raw_json_value},
4};
5#[cfg(feature = "unstable-msc3381")]
6use ruma_events::{
7    poll::{start::PollStartEventContent, unstable_start::UnstablePollStartEventContent},
8    room::encrypted::Replacement,
9};
10use ruma_macros::{EventEnumFromEvent, event_enum};
11use serde::{Deserialize, Serialize, de};
12use serde_json::value::RawValue as RawJsonValue;
13
14use super::room::encrypted;
15
16/// Event types that servers should send as [stripped state] to help clients identify a room when
17/// they can't access the full room state.
18///
19/// [stripped state]: https://spec.matrix.org/v1.19/client-server-api/#stripped-state
20pub const RECOMMENDED_STRIPPED_STATE_EVENT_TYPES: &[StateEventType] = &[
21    StateEventType::RoomCreate,
22    StateEventType::RoomName,
23    StateEventType::RoomAvatar,
24    StateEventType::RoomTopic,
25    StateEventType::RoomJoinRules,
26    StateEventType::RoomCanonicalAlias,
27    StateEventType::RoomEncryption,
28];
29
30/// Event types that servers should transfer upon [room upgrade]. The exact details for what is
31/// transferred is left as an implementation detail.
32///
33/// [room upgrade]: https://spec.matrix.org/v1.19/client-server-api/#server-behaviour-21
34pub const RECOMMENDED_TRANSFERABLE_STATE_EVENT_TYPES: &[StateEventType] = &[
35    StateEventType::RoomServerAcl,
36    StateEventType::RoomEncryption,
37    StateEventType::RoomName,
38    StateEventType::RoomAvatar,
39    StateEventType::RoomTopic,
40    StateEventType::RoomGuestAccess,
41    StateEventType::RoomHistoryVisibility,
42    StateEventType::RoomJoinRules,
43    StateEventType::RoomPowerLevels,
44];
45
46event_enum! {
47    /// Any global account data event.
48    enum GlobalAccountData {
49        "m.direct" => super::direct,
50        #[cfg(feature = "unstable-msc4359")]
51        #[ruma_enum(ident = DoNotDisturb, alias = "m.do_not_disturb")]
52        "dm.filament.do_not_disturb" => super::do_not_disturb,
53        "m.identity_server" => super::identity_server,
54        "m.invite_permission_config" => super::invite_permission_config,
55        #[cfg(feature = "unstable-msc4380")]
56        #[ruma_enum(ident = UnstableInvitePermissionConfig)]
57        "org.matrix.msc4380.invite_permission_config" => super::invite_permission_config,
58        "m.ignored_user_list" => super::ignored_user_list,
59        "m.image_pack.rooms" => super::image_pack::rooms,
60        "m.push_rules" => super::push_rules,
61        "m.secret_storage.default_key" => super::secret_storage::default_key,
62        "m.secret_storage.key.*" => super::secret_storage::key,
63        #[cfg(feature = "unstable-msc4278")]
64        "m.media_preview_config" => super::media_preview_config,
65        #[cfg(feature = "unstable-msc4278")]
66        #[ruma_enum(ident = UnstableMediaPreviewConfig)]
67        "io.element.msc4278.media_preview_config" => super::media_preview_config,
68        "m.recent_emoji" => super::recent_emoji,
69        "m.key_backup" => super::key_backup,
70    }
71
72    /// Any room account data event.
73    enum RoomAccountData {
74        "m.fully_read" => super::fully_read,
75        "m.tag" => super::tag,
76        "m.marked_unread" => super::marked_unread,
77        #[cfg(feature = "unstable-msc2867")]
78        #[ruma_enum(ident = UnstableMarkedUnread)]
79        "com.famedly.marked_unread" => super::marked_unread,
80        #[cfg(feature = "unstable-msc4278")]
81        "m.media_preview_config" => super::media_preview_config,
82        #[cfg(feature = "unstable-msc4278")]
83        #[ruma_enum(ident = UnstableMediaPreviewConfig)]
84        "io.element.msc4278.media_preview_config" => super::media_preview_config,
85        #[cfg(feature = "unstable-msc3230")]
86        #[ruma_enum(alias = "m.space_order")]
87        "org.matrix.msc3230.space_order" => super::space_order,
88    }
89
90    /// Any ephemeral room event.
91    enum EphemeralRoom {
92        "m.receipt" => super::receipt,
93        "m.typing" => super::typing,
94    }
95
96    /// Any message-like event.
97    enum MessageLike {
98        #[cfg(feature = "unstable-msc3927")]
99        #[ruma_enum(alias = "m.audio")]
100        "org.matrix.msc1767.audio" => super::audio,
101        "m.call.answer" => super::call::answer,
102        "m.call.invite" => super::call::invite,
103        "m.call.hangup" => super::call::hangup,
104        "m.call.candidates" => super::call::candidates,
105        "m.call.negotiate" => super::call::negotiate,
106        "m.call.reject" => super::call::reject,
107        #[ruma_enum(alias = "org.matrix.call.sdp_stream_metadata_changed")]
108        "m.call.sdp_stream_metadata_changed" => super::call::sdp_stream_metadata_changed,
109        "m.call.select_answer" => super::call::select_answer,
110        #[cfg(feature = "unstable-msc3954")]
111        #[ruma_enum(alias = "m.emote")]
112        "org.matrix.msc1767.emote" => super::emote,
113        #[cfg(feature = "unstable-msc3956")]
114        #[ruma_enum(alias = "m.encrypted")]
115        "org.matrix.msc1767.encrypted" => super::encrypted,
116        #[cfg(feature = "unstable-msc3551")]
117        #[ruma_enum(alias = "m.file")]
118        "org.matrix.msc1767.file" => super::file,
119        #[cfg(feature = "unstable-msc3552")]
120        #[ruma_enum(alias = "m.image")]
121        "org.matrix.msc1767.image" => super::image,
122        "m.key.verification.ready" => super::key::verification::ready,
123        "m.key.verification.start" => super::key::verification::start,
124        "m.key.verification.cancel" => super::key::verification::cancel,
125        "m.key.verification.accept" => super::key::verification::accept,
126        "m.key.verification.key" => super::key::verification::key,
127        "m.key.verification.mac" => super::key::verification::mac,
128        "m.key.verification.done" => super::key::verification::done,
129        #[cfg(feature = "unstable-msc3488")]
130        "m.location" => super::location,
131        #[cfg(feature = "unstable-msc1767")]
132        #[ruma_enum(alias = "m.message")]
133        "org.matrix.msc1767.message" => super::message,
134        #[cfg(feature = "unstable-msc3381")]
135        "m.poll.start" => super::poll::start,
136        #[cfg(feature = "unstable-msc3381")]
137        #[ruma_enum(ident = UnstablePollStart)]
138        "org.matrix.msc3381.poll.start" => super::poll::unstable_start,
139        #[cfg(feature = "unstable-msc3381")]
140        "m.poll.response" => super::poll::response,
141        #[cfg(feature = "unstable-msc3381")]
142        #[ruma_enum(ident = UnstablePollResponse)]
143        "org.matrix.msc3381.poll.response" => super::poll::unstable_response,
144        #[cfg(feature = "unstable-msc3381")]
145        "m.poll.end" => super::poll::end,
146        #[cfg(feature = "unstable-msc3381")]
147        #[ruma_enum(ident = UnstablePollEnd)]
148        "org.matrix.msc3381.poll.end" => super::poll::unstable_end,
149        #[cfg(feature = "unstable-msc3489")]
150        #[ruma_enum(alias = "m.beacon")]
151        "org.matrix.msc3672.beacon" => super::beacon,
152        "m.reaction" => super::reaction,
153        "m.room.encrypted" => super::room::encrypted,
154        "m.room.message" => super::room::message,
155        "m.room.redaction" => super::room::redaction,
156        "m.sticker" => super::sticker,
157        #[cfg(feature = "unstable-msc3553")]
158        #[ruma_enum(alias = "m.video")]
159        "org.matrix.msc1767.video" => super::video,
160        #[cfg(feature = "unstable-msc3245")]
161        #[ruma_enum(alias = "m.voice")]
162        "org.matrix.msc3245.voice.v2" => super::voice,
163        #[cfg(feature = "unstable-msc4075")]
164        #[ruma_enum(alias = "m.call.notify")]
165        #[allow(deprecated)]
166        "org.matrix.msc4075.call.notify" => super::call::notify,
167        #[cfg(feature = "unstable-msc4075")]
168        #[ruma_enum(alias = "m.rtc.notification")]
169        "org.matrix.msc4075.rtc.notification" => super::rtc::notification,
170        #[cfg(feature = "unstable-msc4310")]
171        #[ruma_enum(alias = "m.rtc.decline")]
172        "org.matrix.msc4310.rtc.decline" => super::rtc::decline,
173    }
174
175    /// Any state event.
176    enum State {
177        "m.policy.rule.room" => super::policy::rule::room,
178        "m.policy.rule.server" => super::policy::rule::server,
179        "m.policy.rule.user" => super::policy::rule::user,
180        "m.room.avatar" => super::room::avatar,
181        "m.room.canonical_alias" => super::room::canonical_alias,
182        "m.room.create" => super::room::create,
183        "m.room.encryption" => super::room::encryption,
184        #[cfg(feature = "unstable-msc4362")]
185        "m.room.encrypted" => super::room::encrypted::unstable_state,
186        "m.room.guest_access" => super::room::guest_access,
187        "m.room.history_visibility" => super::room::history_visibility,
188        "m.room.image_pack" => super::room::image_pack,
189        "m.room.join_rules" => super::room::join_rules,
190        #[cfg(feature = "unstable-msc4334")]
191        #[ruma_enum(alias = "m.room.language")]
192        "org.matrix.msc4334.room.language" => super::room::language,
193        "m.room.member" => super::room::member,
194        "m.room.name" => super::room::name,
195        "m.room.pinned_events" => super::room::pinned_events,
196        "m.room.policy" => super::room::policy,
197        "m.room.power_levels" => super::room::power_levels,
198        "m.room.server_acl" => super::room::server_acl,
199        "m.room.third_party_invite" => super::room::third_party_invite,
200        "m.room.tombstone" => super::room::tombstone,
201        "m.room.topic" => super::room::topic,
202        "m.space.child" => super::space::child,
203        "m.space.parent" => super::space::parent,
204        #[cfg(feature = "unstable-msc3489")]
205        #[ruma_enum(alias = "m.beacon_info")]
206        "org.matrix.msc3672.beacon_info" => super::beacon_info,
207        #[cfg(feature = "unstable-msc3401")]
208        #[ruma_enum(alias = "m.call.member")]
209        "org.matrix.msc3401.call.member" => super::call::member,
210        #[cfg(feature = "unstable-msc4171")]
211        #[ruma_enum(alias = "m.member_hints")]
212        "io.element.functional_members" => super::member_hints,
213    }
214
215    /// Any to-device event.
216    enum ToDevice {
217        "m.dummy" => super::dummy,
218        "m.room_key" => super::room_key,
219        #[cfg(feature = "unstable-msc4268")]
220        #[ruma_enum(alias = "m.room_key_bundle")]
221        "io.element.msc4268.room_key_bundle" => super::room_key_bundle,
222        "m.room_key_request" => super::room_key_request,
223        "m.room_key.withheld" => super::room_key::withheld,
224        "m.forwarded_room_key" => super::forwarded_room_key,
225        "m.key.verification.request" => super::key::verification::request,
226        "m.key.verification.ready" => super::key::verification::ready,
227        "m.key.verification.start" => super::key::verification::start,
228        "m.key.verification.cancel" => super::key::verification::cancel,
229        "m.key.verification.accept" => super::key::verification::accept,
230        "m.key.verification.key" => super::key::verification::key,
231        "m.key.verification.mac" => super::key::verification::mac,
232        "m.key.verification.done" => super::key::verification::done,
233        "m.room.encrypted" => super::room::encrypted,
234        "m.secret.request"=> super::secret::request,
235        "m.secret.send" => super::secret::send,
236        #[cfg(feature = "unstable-msc4385")]
237        #[ruma_enum(alias = "m.secret.push")]
238        "io.element.msc4385.secret.push" => super::secret::push,
239        #[cfg(feature = "unstable-msc4471")]
240        #[ruma_enum(alias = "m.stream.subscribe")]
241        "org.matrix.msc4471.stream.subscribe" => super::stream::subscribe,
242        #[cfg(feature = "unstable-msc4471")]
243        #[ruma_enum(alias = "m.stream.cancel")]
244        "org.matrix.msc4471.stream.cancel" => super::stream::cancel,
245        #[cfg(feature = "unstable-msc4471")]
246        #[ruma_enum(alias = "m.stream.update")]
247        "org.matrix.msc4471.stream.update" => super::stream::update,
248    }
249}
250
251macro_rules! timeline_event_accessors {
252    (
253        $(
254            #[doc = $docs:literal]
255            pub fn $field:ident(&self) -> $ty:ty;
256        )*
257    ) => {
258        $(
259            #[doc = $docs]
260            pub fn $field(&self) -> $ty {
261                match self {
262                    Self::MessageLike(ev) => ev.$field(),
263                    Self::State(ev) => ev.$field(),
264                }
265            }
266        )*
267    };
268}
269
270/// Any room event.
271#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
272#[derive(Clone, Debug, EventEnumFromEvent)]
273pub enum AnyTimelineEvent {
274    /// Any message-like event.
275    MessageLike(AnyMessageLikeEvent),
276
277    /// Any state event.
278    State(AnyStateEvent),
279}
280
281impl AnyTimelineEvent {
282    timeline_event_accessors! {
283        /// Returns this event's `origin_server_ts` field.
284        pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
285
286        /// Returns this event's `room_id` field.
287        pub fn room_id(&self) -> &RoomId;
288
289        /// Returns this event's `event_id` field.
290        pub fn event_id(&self) -> &EventId;
291
292        /// Returns this event's `sender` field.
293        pub fn sender(&self) -> &UserId;
294
295        /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
296        pub fn transaction_id(&self) -> Option<&TransactionId>;
297
298        /// Returns whether this event is in its redacted form or not.
299        pub fn is_redacted(&self) -> bool;
300    }
301
302    /// Returns this event's `type`.
303    pub fn event_type(&self) -> TimelineEventType {
304        match self {
305            Self::MessageLike(e) => e.event_type().into(),
306            Self::State(e) => e.event_type().into(),
307        }
308    }
309}
310
311/// Any sync room event.
312///
313/// Sync room events are room event without a `room_id`, as returned in `/sync` responses.
314#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
315#[derive(Clone, Debug, EventEnumFromEvent)]
316pub enum AnySyncTimelineEvent {
317    /// Any sync message-like event.
318    MessageLike(AnySyncMessageLikeEvent),
319
320    /// Any sync state event.
321    State(AnySyncStateEvent),
322}
323
324impl AnySyncTimelineEvent {
325    timeline_event_accessors! {
326        /// Returns this event's `origin_server_ts` field.
327        pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
328
329        /// Returns this event's `event_id` field.
330        pub fn event_id(&self) -> &EventId;
331
332        /// Returns this event's `sender` field.
333        pub fn sender(&self) -> &UserId;
334
335        /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
336        pub fn transaction_id(&self) -> Option<&TransactionId>;
337
338        /// Returns whether this event is in its redacted form or not.
339        pub fn is_redacted(&self) -> bool;
340    }
341
342    /// Returns this event's `type`.
343    pub fn event_type(&self) -> TimelineEventType {
344        match self {
345            Self::MessageLike(e) => e.event_type().into(),
346            Self::State(e) => e.event_type().into(),
347        }
348    }
349
350    /// Converts `self` to an `AnyTimelineEvent` by adding the given a room ID.
351    pub fn into_full_event(self, room_id: OwnedRoomId) -> AnyTimelineEvent {
352        match self {
353            Self::MessageLike(ev) => AnyTimelineEvent::MessageLike(ev.into_full_event(room_id)),
354            Self::State(ev) => AnyTimelineEvent::State(ev.into_full_event(room_id)),
355        }
356    }
357}
358
359impl From<AnyTimelineEvent> for AnySyncTimelineEvent {
360    fn from(ev: AnyTimelineEvent) -> Self {
361        match ev {
362            AnyTimelineEvent::MessageLike(ev) => Self::MessageLike(ev.into()),
363            AnyTimelineEvent::State(ev) => Self::State(ev.into()),
364        }
365    }
366}
367
368/// Any room event content.
369#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
370#[derive(Clone, Debug, EventEnumFromEvent, Serialize)]
371#[serde(untagged)]
372pub enum AnyTimelineEventContent {
373    /// Any message-like event content.
374    MessageLike(AnyMessageLikeEventContent),
375
376    /// Any state event content.
377    State(AnyStateEventContent),
378}
379
380impl AnyTimelineEventContent {
381    /// Get the event's type
382    pub fn event_type(&self) -> TimelineEventType {
383        match self {
384            Self::MessageLike(content) => {
385                <AnyMessageLikeEventContent as crate::MessageLikeEventContent>::event_type(content)
386                    .into()
387            }
388            Self::State(content) => {
389                <AnyStateEventContent as crate::StateEventContent>::event_type(content).into()
390            }
391        }
392    }
393}
394
395impl JsonCastable<AnyTimelineEventContent> for AnyMessageLikeEventContent {}
396impl JsonCastable<AnyTimelineEventContent> for AnyStateEventContent {}
397
398#[derive(Deserialize)]
399#[allow(clippy::exhaustive_structs)]
400struct EventDeHelper {
401    state_key: Option<de::IgnoredAny>,
402}
403
404impl<'de> Deserialize<'de> for AnyTimelineEvent {
405    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
406    where
407        D: de::Deserializer<'de>,
408    {
409        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
410        let EventDeHelper { state_key } = from_raw_json_value(&json)?;
411
412        if state_key.is_some() {
413            Ok(AnyTimelineEvent::State(from_raw_json_value(&json)?))
414        } else {
415            Ok(AnyTimelineEvent::MessageLike(from_raw_json_value(&json)?))
416        }
417    }
418}
419
420impl<'de> Deserialize<'de> for AnySyncTimelineEvent {
421    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
422    where
423        D: de::Deserializer<'de>,
424    {
425        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
426        let EventDeHelper { state_key } = from_raw_json_value(&json)?;
427
428        if state_key.is_some() {
429            Ok(AnySyncTimelineEvent::State(from_raw_json_value(&json)?))
430        } else {
431            Ok(AnySyncTimelineEvent::MessageLike(from_raw_json_value(&json)?))
432        }
433    }
434}
435
436impl AnyMessageLikeEventContent {
437    /// Get a copy of the event's `m.relates_to` field, if any.
438    ///
439    /// This is a helper function intended for encryption. There should not be a reason to access
440    /// `m.relates_to` without first destructuring an `AnyMessageLikeEventContent` otherwise.
441    pub fn relation(&self) -> Option<encrypted::Relation> {
442        #[cfg(feature = "unstable-msc3489")]
443        use super::beacon::BeaconEventContent;
444        use super::key::verification::{
445            accept::KeyVerificationAcceptEventContent, cancel::KeyVerificationCancelEventContent,
446            done::KeyVerificationDoneEventContent, key::KeyVerificationKeyEventContent,
447            mac::KeyVerificationMacEventContent, ready::KeyVerificationReadyEventContent,
448            start::KeyVerificationStartEventContent,
449        };
450        #[cfg(feature = "unstable-msc3381")]
451        use super::poll::{
452            end::PollEndEventContent, response::PollResponseEventContent,
453            unstable_end::UnstablePollEndEventContent,
454            unstable_response::UnstablePollResponseEventContent,
455        };
456
457        match self {
458            #[rustfmt::skip]
459            Self::KeyVerificationReady(KeyVerificationReadyEventContent { relates_to, .. })
460            | Self::KeyVerificationStart(KeyVerificationStartEventContent { relates_to, .. })
461            | Self::KeyVerificationCancel(KeyVerificationCancelEventContent { relates_to, .. })
462            | Self::KeyVerificationAccept(KeyVerificationAcceptEventContent { relates_to, .. })
463            | Self::KeyVerificationKey(KeyVerificationKeyEventContent { relates_to, .. })
464            | Self::KeyVerificationMac(KeyVerificationMacEventContent { relates_to, .. })
465            | Self::KeyVerificationDone(KeyVerificationDoneEventContent { relates_to, .. }) => {
466                Some(encrypted::Relation::Reference(relates_to.clone()))
467            },
468            Self::Reaction(ev) => Some(encrypted::Relation::Annotation(ev.relates_to.clone())),
469            Self::RoomEncrypted(ev) => ev.relates_to.clone(),
470            Self::RoomMessage(ev) => ev.relates_to.clone().map(Into::into),
471            #[cfg(feature = "unstable-msc1767")]
472            Self::Message(ev) => ev.relates_to.clone().map(Into::into),
473            #[cfg(feature = "unstable-msc3954")]
474            Self::Emote(ev) => ev.relates_to.clone().map(Into::into),
475            #[cfg(feature = "unstable-msc3956")]
476            Self::Encrypted(ev) => ev.relates_to.clone(),
477            #[cfg(feature = "unstable-msc3245")]
478            Self::Voice(ev) => ev.relates_to.clone().map(Into::into),
479            #[cfg(feature = "unstable-msc3927")]
480            Self::Audio(ev) => ev.relates_to.clone().map(Into::into),
481            #[cfg(feature = "unstable-msc3488")]
482            Self::Location(ev) => ev.relates_to.clone().map(Into::into),
483            #[cfg(feature = "unstable-msc3551")]
484            Self::File(ev) => ev.relates_to.clone().map(Into::into),
485            #[cfg(feature = "unstable-msc3552")]
486            Self::Image(ev) => ev.relates_to.clone().map(Into::into),
487            #[cfg(feature = "unstable-msc3553")]
488            Self::Video(ev) => ev.relates_to.clone().map(Into::into),
489            #[cfg(feature = "unstable-msc3381")]
490            Self::PollResponse(PollResponseEventContent { relates_to, .. })
491            | Self::UnstablePollResponse(UnstablePollResponseEventContent { relates_to, .. })
492            | Self::PollEnd(PollEndEventContent { relates_to, .. })
493            | Self::UnstablePollEnd(UnstablePollEndEventContent { relates_to, .. }) => {
494                Some(encrypted::Relation::Reference(relates_to.clone()))
495            }
496            #[cfg(feature = "unstable-msc3489")]
497            Self::Beacon(BeaconEventContent { relates_to, .. }) => {
498                Some(encrypted::Relation::Reference(relates_to.clone()))
499            }
500            #[cfg(feature = "unstable-msc3381")]
501            Self::UnstablePollStart(UnstablePollStartEventContent::New(content)) => {
502                content.relates_to.clone().map(Into::into)
503            }
504            #[cfg(feature = "unstable-msc3381")]
505            Self::UnstablePollStart(UnstablePollStartEventContent::Replacement(content)) => {
506                Some(encrypted::Relation::Replacement(Replacement::new(
507                    content.relates_to.event_id.clone(),
508                )))
509            }
510            #[cfg(feature = "unstable-msc3381")]
511            Self::PollStart(PollStartEventContent { relates_to, .. }) => {
512                relates_to.clone().map(Into::into)
513            }
514            #[cfg(feature = "unstable-msc4075")]
515            Self::CallNotify(_) => None,
516            #[cfg(feature = "unstable-msc4075")]
517            Self::RtcNotification(ev) => ev.relates_to.clone().map(encrypted::Relation::Reference),
518            #[cfg(feature = "unstable-msc4310")]
519            Self::RtcDecline(ev) => Some(encrypted::Relation::Reference(ev.relates_to.clone())),
520            Self::CallSdpStreamMetadataChanged(_)
521            | Self::CallNegotiate(_)
522            | Self::CallReject(_)
523            | Self::CallSelectAnswer(_)
524            | Self::CallAnswer(_)
525            | Self::CallInvite(_)
526            | Self::CallHangup(_)
527            | Self::CallCandidates(_)
528            | Self::RoomRedaction(_)
529            | Self::Sticker(_)
530            | Self::_Custom { .. } => None,
531        }
532    }
533}