twilight_model/application/interaction/
mod.rs

1//! Used when receiving interactions through gateway or webhooks.
2//!
3//! See [Discord Docs/Receiving and Responding].
4//!
5//! [Discord Docs/Receiving and Responding]: https://discord.com/developers/docs/interactions/receiving-and-responding
6
7pub mod application_command;
8pub mod message_component;
9pub mod modal;
10
11mod context_type;
12mod interaction_type;
13mod metadata;
14mod resolved;
15
16pub use self::{
17    context_type::InteractionContextType,
18    interaction_type::InteractionType,
19    metadata::InteractionMetadata,
20    resolved::{InteractionChannel, InteractionDataResolved, InteractionMember},
21};
22
23use self::{
24    application_command::CommandData, message_component::MessageComponentInteractionData,
25    modal::ModalInteractionData,
26};
27use crate::{
28    channel::{Channel, Message},
29    guild::{GuildFeature, PartialMember, Permissions},
30    id::{
31        marker::{ApplicationMarker, ChannelMarker, GuildMarker, InteractionMarker, UserMarker},
32        AnonymizableId, Id,
33    },
34    oauth::ApplicationIntegrationMap,
35    user::User,
36};
37use serde::{
38    de::{Error as DeError, IgnoredAny, MapAccess, Visitor},
39    Deserialize, Deserializer, Serialize,
40};
41use serde_value::{DeserializerError, Value};
42use std::fmt::{Formatter, Result as FmtResult};
43
44use super::monetization::Entitlement;
45
46/// Payload received when a user executes an interaction.
47///
48/// See [Discord Docs/Interaction Object].
49///
50/// [Discord Docs/Interaction Object]: https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-structure
51#[derive(Clone, Debug, PartialEq, Serialize)]
52pub struct Interaction {
53    /// App's permissions in the channel the interaction was sent from.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub app_permissions: Option<Permissions>,
56    /// ID of the associated application.
57    pub application_id: Id<ApplicationMarker>,
58    /// Mapping of installation contexts that the interaction was
59    /// authorized for to related user or guild IDs.
60    pub authorizing_integration_owners:
61        ApplicationIntegrationMap<AnonymizableId<GuildMarker>, Id<UserMarker>>,
62    /// The channel the interaction was invoked in.
63    ///
64    /// Present on all interactions types, except [`Ping`].
65    ///
66    /// [`Ping`]: InteractionType::Ping
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub channel: Option<Channel>,
69    /// ID of the channel the interaction was invoked in.
70    ///
71    /// Present on all interactions types, except [`Ping`].
72    ///
73    /// [`Ping`]: InteractionType::Ping
74    #[serde(skip_serializing_if = "Option::is_none")]
75    #[deprecated(
76        note = "channel_id is deprecated in the discord API and will no be sent in the future, users should use the channel field instead."
77    )]
78    pub channel_id: Option<Id<ChannelMarker>>,
79    /// Context where the interaction was triggered from.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub context: Option<InteractionContextType>,
82    /// Data from the interaction.
83    ///
84    /// This field present on [`ApplicationCommand`], [`MessageComponent`],
85    /// [`ApplicationCommandAutocomplete`] and [`ModalSubmit`] interactions.
86    /// The inner enum variant matches the interaction type.
87    ///
88    /// [`ApplicationCommand`]: InteractionType::ApplicationCommand
89    /// [`MessageComponent`]: InteractionType::MessageComponent
90    /// [`ApplicationCommandAutocomplete`]: InteractionType::ApplicationCommandAutocomplete
91    /// [`ModalSubmit`]: InteractionType::ModalSubmit
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub data: Option<InteractionData>,
94    /// For monetized apps, any entitlements for the invoking user, representing access to premium SKUs
95    pub entitlements: Vec<Entitlement>,
96    /// Guild that the interaction was sent from.
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub guild: Option<InteractionPartialGuild>,
99    /// ID of the guild the interaction was invoked in.
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub guild_id: Option<Id<GuildMarker>>,
102    /// Guild’s preferred locale.
103    ///
104    /// Present when the interaction is invoked in a guild.
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub guild_locale: Option<String>,
107    /// ID of the interaction.
108    pub id: Id<InteractionMarker>,
109    /// Type of interaction.
110    #[serde(rename = "type")]
111    pub kind: InteractionType,
112    /// Selected language of the user who invoked the interaction.
113    ///
114    /// Present on all interactions types, except [`Ping`].
115    ///
116    /// [`Ping`]: InteractionType::Ping
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub locale: Option<String>,
119    /// Member that invoked the interaction.
120    ///
121    /// Present when the interaction is invoked in a guild.
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub member: Option<PartialMember>,
124    /// Message attached to the interaction.
125    ///
126    /// Present on [`MessageComponent`] interactions.
127    ///
128    /// [`MessageComponent`]: InteractionType::MessageComponent
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub message: Option<Message>,
131    /// Token for responding to the interaction.
132    pub token: String,
133    /// User that invoked the interaction.
134    ///
135    /// Present when the interaction is invoked in a direct message.
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub user: Option<User>,
138}
139
140impl Interaction {
141    /// ID of the user that invoked the interaction.
142    ///
143    /// This will first check for the [`member`]'s
144    /// [`user`][`PartialMember::user`]'s ID and then, if not present, check the
145    /// [`user`]'s ID.
146    ///
147    /// [`member`]: Self::member
148    /// [`user`]: Self::user
149    pub const fn author_id(&self) -> Option<Id<UserMarker>> {
150        if let Some(user) = self.author() {
151            Some(user.id)
152        } else {
153            None
154        }
155    }
156
157    /// The user that invoked the interaction.
158    ///
159    /// This will first check for the [`member`]'s
160    /// [`user`][`PartialMember::user`] and then, if not present, check the
161    /// [`user`].
162    ///
163    /// [`member`]: Self::member
164    /// [`user`]: Self::user
165    pub const fn author(&self) -> Option<&User> {
166        match self.member.as_ref() {
167            Some(member) if member.user.is_some() => member.user.as_ref(),
168            _ => self.user.as_ref(),
169        }
170    }
171
172    /// Whether the interaction was invoked in a DM.
173    pub const fn is_dm(&self) -> bool {
174        self.user.is_some()
175    }
176
177    /// Whether the interaction was invoked in a guild.
178    pub const fn is_guild(&self) -> bool {
179        self.member.is_some()
180    }
181}
182
183impl<'de> Deserialize<'de> for Interaction {
184    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
185        deserializer.deserialize_map(InteractionVisitor)
186    }
187}
188
189#[derive(Debug, Deserialize)]
190#[serde(field_identifier, rename_all = "snake_case")]
191enum InteractionField {
192    AppPermissions,
193    ApplicationId,
194    Context,
195    Channel,
196    ChannelId,
197    Data,
198    Entitlements,
199    Guild,
200    GuildId,
201    GuildLocale,
202    Id,
203    Locale,
204    Member,
205    Message,
206    Token,
207    Type,
208    User,
209    Version,
210    AuthorizingIntegrationOwners,
211}
212
213struct InteractionVisitor;
214
215impl<'de> Visitor<'de> for InteractionVisitor {
216    type Value = Interaction;
217
218    fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
219        f.write_str("enum Interaction")
220    }
221
222    #[allow(clippy::too_many_lines, deprecated)]
223    fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<Self::Value, V::Error> {
224        let mut app_permissions: Option<Permissions> = None;
225        let mut application_id: Option<Id<ApplicationMarker>> = None;
226        let mut channel: Option<Channel> = None;
227        let mut channel_id: Option<Id<ChannelMarker>> = None;
228        let mut context: Option<InteractionContextType> = None;
229        let mut data: Option<Value> = None;
230        let mut entitlements: Option<Vec<Entitlement>> = None;
231        let mut guild: Option<InteractionPartialGuild> = None;
232        let mut guild_id: Option<Id<GuildMarker>> = None;
233        let mut guild_locale: Option<String> = None;
234        let mut id: Option<Id<InteractionMarker>> = None;
235        let mut kind: Option<InteractionType> = None;
236        let mut locale: Option<String> = None;
237        let mut member: Option<PartialMember> = None;
238        let mut message: Option<Message> = None;
239        let mut token: Option<String> = None;
240        let mut user: Option<User> = None;
241        let mut authorizing_integration_owners: Option<
242            ApplicationIntegrationMap<AnonymizableId<GuildMarker>, Id<UserMarker>>,
243        > = None;
244
245        loop {
246            let key = match map.next_key() {
247                Ok(Some(key)) => key,
248                Ok(None) => break,
249                Err(_) => {
250                    map.next_value::<IgnoredAny>()?;
251
252                    continue;
253                }
254            };
255
256            match key {
257                InteractionField::AppPermissions => {
258                    if app_permissions.is_some() {
259                        return Err(DeError::duplicate_field("app_permissions"));
260                    }
261
262                    app_permissions = map.next_value()?;
263                }
264                InteractionField::ApplicationId => {
265                    if application_id.is_some() {
266                        return Err(DeError::duplicate_field("application_id"));
267                    }
268
269                    application_id = Some(map.next_value()?);
270                }
271                InteractionField::Context => {
272                    if context.is_some() {
273                        return Err(DeError::duplicate_field("context"));
274                    }
275
276                    context = map.next_value()?;
277                }
278                InteractionField::Channel => {
279                    if channel.is_some() {
280                        return Err(DeError::duplicate_field("channel"));
281                    }
282
283                    channel = map.next_value()?;
284                }
285                InteractionField::ChannelId => {
286                    if channel_id.is_some() {
287                        return Err(DeError::duplicate_field("channel_id"));
288                    }
289
290                    channel_id = map.next_value()?;
291                }
292                InteractionField::Data => {
293                    if data.is_some() {
294                        return Err(DeError::duplicate_field("data"));
295                    }
296
297                    data = map.next_value()?;
298                }
299                InteractionField::Entitlements => {
300                    if entitlements.is_some() {
301                        return Err(DeError::duplicate_field("entitlements"));
302                    }
303
304                    entitlements = map.next_value()?;
305                }
306                InteractionField::Guild => {
307                    if guild.is_some() {
308                        return Err(DeError::duplicate_field("guild"));
309                    }
310
311                    guild = map.next_value()?;
312                }
313                InteractionField::GuildId => {
314                    if guild_id.is_some() {
315                        return Err(DeError::duplicate_field("guild_id"));
316                    }
317
318                    guild_id = map.next_value()?;
319                }
320                InteractionField::GuildLocale => {
321                    if guild_locale.is_some() {
322                        return Err(DeError::duplicate_field("guild_locale"));
323                    }
324
325                    guild_locale = map.next_value()?;
326                }
327                InteractionField::Id => {
328                    if id.is_some() {
329                        return Err(DeError::duplicate_field("id"));
330                    }
331
332                    id = Some(map.next_value()?);
333                }
334                InteractionField::Locale => {
335                    if locale.is_some() {
336                        return Err(DeError::duplicate_field("locale"));
337                    }
338
339                    locale = map.next_value()?;
340                }
341                InteractionField::Member => {
342                    if member.is_some() {
343                        return Err(DeError::duplicate_field("member"));
344                    }
345
346                    member = map.next_value()?;
347                }
348                InteractionField::Message => {
349                    if message.is_some() {
350                        return Err(DeError::duplicate_field("message"));
351                    }
352
353                    message = map.next_value()?;
354                }
355                InteractionField::Token => {
356                    if token.is_some() {
357                        return Err(DeError::duplicate_field("token"));
358                    }
359
360                    token = Some(map.next_value()?);
361                }
362                InteractionField::Type => {
363                    if kind.is_some() {
364                        return Err(DeError::duplicate_field("kind"));
365                    }
366
367                    kind = Some(map.next_value()?);
368                }
369                InteractionField::User => {
370                    if user.is_some() {
371                        return Err(DeError::duplicate_field("user"));
372                    }
373
374                    user = map.next_value()?;
375                }
376                InteractionField::Version => {
377                    // Ignoring the version field.
378                    map.next_value::<IgnoredAny>()?;
379                }
380                InteractionField::AuthorizingIntegrationOwners => {
381                    if authorizing_integration_owners.is_some() {
382                        return Err(DeError::duplicate_field("authorizing_integration_owners"));
383                    }
384
385                    authorizing_integration_owners = map.next_value()?;
386                }
387            }
388        }
389
390        let application_id =
391            application_id.ok_or_else(|| DeError::missing_field("application_id"))?;
392        let authorizing_integration_owners = authorizing_integration_owners
393            .ok_or_else(|| DeError::missing_field("authorizing_integration_owners"))?;
394        let id = id.ok_or_else(|| DeError::missing_field("id"))?;
395        let token = token.ok_or_else(|| DeError::missing_field("token"))?;
396        let kind = kind.ok_or_else(|| DeError::missing_field("kind"))?;
397
398        let data = match kind {
399            InteractionType::Ping => None,
400            InteractionType::ApplicationCommand => {
401                let data = data
402                    .ok_or_else(|| DeError::missing_field("data"))?
403                    .deserialize_into()
404                    .map_err(DeserializerError::into_error)?;
405
406                Some(InteractionData::ApplicationCommand(data))
407            }
408            InteractionType::MessageComponent => {
409                let data = data
410                    .ok_or_else(|| DeError::missing_field("data"))?
411                    .deserialize_into()
412                    .map_err(DeserializerError::into_error)?;
413
414                Some(InteractionData::MessageComponent(data))
415            }
416            InteractionType::ApplicationCommandAutocomplete => {
417                let data = data
418                    .ok_or_else(|| DeError::missing_field("data"))?
419                    .deserialize_into()
420                    .map_err(DeserializerError::into_error)?;
421
422                Some(InteractionData::ApplicationCommand(data))
423            }
424            InteractionType::ModalSubmit => {
425                let data = data
426                    .ok_or_else(|| DeError::missing_field("data"))?
427                    .deserialize_into()
428                    .map_err(DeserializerError::into_error)?;
429
430                Some(InteractionData::ModalSubmit(data))
431            }
432        };
433
434        let entitlements = entitlements.unwrap_or_default();
435
436        Ok(Self::Value {
437            app_permissions,
438            application_id,
439            authorizing_integration_owners,
440            channel,
441            channel_id,
442            context,
443            data,
444            entitlements,
445            guild,
446            guild_id,
447            guild_locale,
448            id,
449            kind,
450            locale,
451            member,
452            message,
453            token,
454            user,
455        })
456    }
457}
458
459/// Additional [`Interaction`] data, such as the invoking user.
460#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
461#[non_exhaustive]
462#[serde(untagged)]
463pub enum InteractionData {
464    /// Data received for the [`ApplicationCommand`] and [`ApplicationCommandAutocomplete`]
465    /// interaction types.
466    ///
467    /// [`ApplicationCommand`]: InteractionType::ApplicationCommand
468    /// [`ApplicationCommandAutocomplete`]: InteractionType::ApplicationCommandAutocomplete
469    ApplicationCommand(Box<CommandData>),
470    /// Data received for the [`MessageComponent`] interaction type.
471    ///
472    /// [`MessageComponent`]: InteractionType::MessageComponent
473    MessageComponent(Box<MessageComponentInteractionData>),
474    /// Data received for the [`ModalSubmit`] interaction type.
475    ///
476    /// [`ModalSubmit`]: InteractionType::ModalSubmit
477    ModalSubmit(ModalInteractionData),
478}
479
480/// Partial guild containing only the fields sent in the partial guild
481/// in interactions.
482///
483/// # Note that the field `locale` does not exists on the full guild
484/// object, and is only found here. See
485/// <https://github.com/discord/discord-api-docs/issues/6938> for more
486/// info.
487#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize, Hash)]
488pub struct InteractionPartialGuild {
489    /// Id of the guild.
490    pub id: Option<Id<GuildMarker>>,
491    /// Enabled guild features
492    pub features: Option<Vec<GuildFeature>>,
493    pub locale: Option<String>,
494}
495
496#[cfg(test)]
497mod tests {
498    use super::{
499        application_command::{CommandData, CommandDataOption, CommandOptionValue},
500        Interaction, InteractionData, InteractionDataResolved, InteractionMember, InteractionType,
501    };
502    use crate::{
503        application::{
504            command::{CommandOptionType, CommandType},
505            monetization::{entitlement::Entitlement, EntitlementType},
506        },
507        channel::Channel,
508        guild::{MemberFlags, PartialMember, Permissions},
509        id::Id,
510        oauth::ApplicationIntegrationMap,
511        test::image_hash,
512        user::User,
513        util::datetime::{Timestamp, TimestampParseError},
514    };
515    use serde_test::Token;
516    use std::{collections::HashMap, str::FromStr};
517
518    #[test]
519    #[allow(clippy::too_many_lines, deprecated)]
520    fn test_interaction_full() -> Result<(), TimestampParseError> {
521        let joined_at = Some(Timestamp::from_str("2020-01-01T00:00:00.000000+00:00")?);
522        let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
523
524        let value = Interaction {
525            app_permissions: Some(Permissions::SEND_MESSAGES),
526            application_id: Id::new(100),
527            authorizing_integration_owners: ApplicationIntegrationMap {
528                guild: None,
529                user: None,
530            },
531            channel: Some(Channel {
532                bitrate: None,
533                guild_id: None,
534                id: Id::new(400),
535                kind: crate::channel::ChannelType::GuildText,
536                last_message_id: None,
537                last_pin_timestamp: None,
538                name: None,
539                nsfw: None,
540                owner_id: None,
541                parent_id: None,
542                permission_overwrites: None,
543                position: None,
544                rate_limit_per_user: None,
545                recipients: None,
546                rtc_region: None,
547                topic: None,
548                user_limit: None,
549                application_id: None,
550                applied_tags: None,
551                available_tags: None,
552                default_auto_archive_duration: None,
553                default_forum_layout: None,
554                default_reaction_emoji: None,
555                default_sort_order: None,
556                default_thread_rate_limit_per_user: None,
557                flags: None,
558                icon: None,
559                invitable: None,
560                managed: None,
561                member: None,
562                member_count: None,
563                message_count: None,
564                newly_created: None,
565                thread_metadata: None,
566                video_quality_mode: None,
567            }),
568            channel_id: Some(Id::new(200)),
569            context: None,
570            data: Some(InteractionData::ApplicationCommand(Box::new(CommandData {
571                guild_id: None,
572                id: Id::new(300),
573                name: "command name".into(),
574                kind: CommandType::ChatInput,
575                options: Vec::from([CommandDataOption {
576                    name: "member".into(),
577                    value: CommandOptionValue::User(Id::new(600)),
578                }]),
579                resolved: Some(InteractionDataResolved {
580                    attachments: HashMap::new(),
581                    channels: HashMap::new(),
582                    members: IntoIterator::into_iter([(
583                        Id::new(600),
584                        InteractionMember {
585                            avatar: None,
586                            communication_disabled_until: None,
587                            flags,
588                            joined_at,
589                            nick: Some("nickname".into()),
590                            pending: false,
591                            permissions: Permissions::empty(),
592                            premium_since: None,
593                            roles: Vec::new(),
594                        },
595                    )])
596                    .collect(),
597                    messages: HashMap::new(),
598                    roles: HashMap::new(),
599                    users: IntoIterator::into_iter([(
600                        Id::new(600),
601                        User {
602                            accent_color: None,
603                            avatar: Some(image_hash::AVATAR),
604                            avatar_decoration: None,
605                            avatar_decoration_data: None,
606                            banner: None,
607                            bot: false,
608                            discriminator: 1111,
609                            email: None,
610                            flags: None,
611                            global_name: Some("test".into()),
612                            id: Id::new(600),
613                            locale: None,
614                            mfa_enabled: None,
615                            name: "username".into(),
616                            premium_type: None,
617                            public_flags: None,
618                            system: None,
619                            verified: None,
620                        },
621                    )])
622                    .collect(),
623                }),
624                target_id: None,
625            }))),
626            entitlements: vec![Entitlement {
627                application_id: Id::new(100),
628                consumed: Some(false),
629                deleted: false,
630                ends_at: None,
631                guild_id: None,
632                id: Id::new(200),
633                kind: EntitlementType::ApplicationSubscription,
634                sku_id: Id::new(300),
635                starts_at: None,
636                user_id: None,
637            }],
638            guild: None,
639            guild_id: Some(Id::new(400)),
640            guild_locale: Some("de".to_owned()),
641            id: Id::new(500),
642            kind: InteractionType::ApplicationCommand,
643            locale: Some("en-GB".to_owned()),
644            member: Some(PartialMember {
645                avatar: None,
646                communication_disabled_until: None,
647                deaf: false,
648                flags,
649                joined_at,
650                mute: false,
651                nick: Some("nickname".into()),
652                permissions: Some(Permissions::empty()),
653                premium_since: None,
654                roles: Vec::new(),
655                user: Some(User {
656                    accent_color: None,
657                    avatar: Some(image_hash::AVATAR),
658                    avatar_decoration: None,
659                    avatar_decoration_data: None,
660                    banner: None,
661                    bot: false,
662                    discriminator: 1111,
663                    email: None,
664                    flags: None,
665                    global_name: Some("test".into()),
666                    id: Id::new(600),
667                    locale: None,
668                    mfa_enabled: None,
669                    name: "username".into(),
670                    premium_type: None,
671                    public_flags: None,
672                    system: None,
673                    verified: None,
674                }),
675            }),
676            message: None,
677            token: "interaction token".into(),
678            user: None,
679        };
680
681        // TODO: switch the `assert_tokens` see #2190
682        serde_test::assert_ser_tokens(
683            &value,
684            &[
685                Token::Struct {
686                    name: "Interaction",
687                    len: 14,
688                },
689                Token::Str("app_permissions"),
690                Token::Some,
691                Token::Str("2048"),
692                Token::Str("application_id"),
693                Token::NewtypeStruct { name: "Id" },
694                Token::Str("100"),
695                Token::Str("authorizing_integration_owners"),
696                Token::Struct {
697                    name: "ApplicationIntegrationMap",
698                    len: 0,
699                },
700                Token::StructEnd,
701                Token::Str("channel"),
702                Token::Some,
703                Token::Struct {
704                    name: "Channel",
705                    len: 2,
706                },
707                Token::Str("id"),
708                Token::NewtypeStruct { name: "Id" },
709                Token::Str("400"),
710                Token::Str("type"),
711                Token::U8(0),
712                Token::StructEnd,
713                Token::Str("channel_id"),
714                Token::Some,
715                Token::NewtypeStruct { name: "Id" },
716                Token::Str("200"),
717                Token::Str("data"),
718                Token::Some,
719                Token::Struct {
720                    name: "CommandData",
721                    len: 5,
722                },
723                Token::Str("id"),
724                Token::NewtypeStruct { name: "Id" },
725                Token::Str("300"),
726                Token::Str("name"),
727                Token::Str("command name"),
728                Token::Str("type"),
729                Token::U8(1),
730                Token::Str("options"),
731                Token::Seq { len: Some(1) },
732                Token::Struct {
733                    name: "CommandDataOption",
734                    len: 3,
735                },
736                Token::Str("name"),
737                Token::Str("member"),
738                Token::Str("type"),
739                Token::U8(CommandOptionType::User as u8),
740                Token::Str("value"),
741                Token::NewtypeStruct { name: "Id" },
742                Token::Str("600"),
743                Token::StructEnd,
744                Token::SeqEnd,
745                Token::Str("resolved"),
746                Token::Some,
747                Token::Struct {
748                    name: "InteractionDataResolved",
749                    len: 2,
750                },
751                Token::Str("members"),
752                Token::Map { len: Some(1) },
753                Token::NewtypeStruct { name: "Id" },
754                Token::Str("600"),
755                Token::Struct {
756                    name: "InteractionMember",
757                    len: 7,
758                },
759                Token::Str("communication_disabled_until"),
760                Token::None,
761                Token::Str("flags"),
762                Token::U64(flags.bits()),
763                Token::Str("joined_at"),
764                Token::Some,
765                Token::Str("2020-01-01T00:00:00.000000+00:00"),
766                Token::Str("nick"),
767                Token::Some,
768                Token::Str("nickname"),
769                Token::Str("pending"),
770                Token::Bool(false),
771                Token::Str("permissions"),
772                Token::Str("0"),
773                Token::Str("roles"),
774                Token::Seq { len: Some(0) },
775                Token::SeqEnd,
776                Token::StructEnd,
777                Token::MapEnd,
778                Token::Str("users"),
779                Token::Map { len: Some(1) },
780                Token::NewtypeStruct { name: "Id" },
781                Token::Str("600"),
782                Token::Struct {
783                    name: "User",
784                    len: 10,
785                },
786                Token::Str("accent_color"),
787                Token::None,
788                Token::Str("avatar"),
789                Token::Some,
790                Token::Str(image_hash::AVATAR_INPUT),
791                Token::Str("avatar_decoration"),
792                Token::None,
793                Token::Str("avatar_decoration_data"),
794                Token::None,
795                Token::Str("banner"),
796                Token::None,
797                Token::Str("bot"),
798                Token::Bool(false),
799                Token::Str("discriminator"),
800                Token::Str("1111"),
801                Token::Str("global_name"),
802                Token::Some,
803                Token::Str("test"),
804                Token::Str("id"),
805                Token::NewtypeStruct { name: "Id" },
806                Token::Str("600"),
807                Token::Str("username"),
808                Token::Str("username"),
809                Token::StructEnd,
810                Token::MapEnd,
811                Token::StructEnd,
812                Token::StructEnd,
813                Token::Str("entitlements"),
814                Token::Seq { len: Some(1) },
815                Token::Struct {
816                    name: "Entitlement",
817                    len: 6,
818                },
819                Token::Str("application_id"),
820                Token::NewtypeStruct { name: "Id" },
821                Token::Str("100"),
822                Token::Str("consumed"),
823                Token::Some,
824                Token::Bool(false),
825                Token::Str("deleted"),
826                Token::Bool(false),
827                Token::Str("id"),
828                Token::NewtypeStruct { name: "Id" },
829                Token::Str("200"),
830                Token::Str("type"),
831                Token::U8(8),
832                Token::Str("sku_id"),
833                Token::NewtypeStruct { name: "Id" },
834                Token::Str("300"),
835                Token::StructEnd,
836                Token::SeqEnd,
837                Token::Str("guild_id"),
838                Token::Some,
839                Token::NewtypeStruct { name: "Id" },
840                Token::Str("400"),
841                Token::Str("guild_locale"),
842                Token::Some,
843                Token::String("de"),
844                Token::Str("id"),
845                Token::NewtypeStruct { name: "Id" },
846                Token::Str("500"),
847                Token::Str("type"),
848                Token::U8(InteractionType::ApplicationCommand as u8),
849                Token::Str("locale"),
850                Token::Some,
851                Token::Str("en-GB"),
852                Token::Str("member"),
853                Token::Some,
854                Token::Struct {
855                    name: "PartialMember",
856                    len: 9,
857                },
858                Token::Str("communication_disabled_until"),
859                Token::None,
860                Token::Str("deaf"),
861                Token::Bool(false),
862                Token::Str("flags"),
863                Token::U64(flags.bits()),
864                Token::Str("joined_at"),
865                Token::Some,
866                Token::Str("2020-01-01T00:00:00.000000+00:00"),
867                Token::Str("mute"),
868                Token::Bool(false),
869                Token::Str("nick"),
870                Token::Some,
871                Token::Str("nickname"),
872                Token::Str("permissions"),
873                Token::Some,
874                Token::Str("0"),
875                Token::Str("roles"),
876                Token::Seq { len: Some(0) },
877                Token::SeqEnd,
878                Token::Str("user"),
879                Token::Some,
880                Token::Struct {
881                    name: "User",
882                    len: 10,
883                },
884                Token::Str("accent_color"),
885                Token::None,
886                Token::Str("avatar"),
887                Token::Some,
888                Token::Str(image_hash::AVATAR_INPUT),
889                Token::Str("avatar_decoration"),
890                Token::None,
891                Token::Str("avatar_decoration_data"),
892                Token::None,
893                Token::Str("banner"),
894                Token::None,
895                Token::Str("bot"),
896                Token::Bool(false),
897                Token::Str("discriminator"),
898                Token::Str("1111"),
899                Token::Str("global_name"),
900                Token::Some,
901                Token::Str("test"),
902                Token::Str("id"),
903                Token::NewtypeStruct { name: "Id" },
904                Token::Str("600"),
905                Token::Str("username"),
906                Token::Str("username"),
907                Token::StructEnd,
908                Token::StructEnd,
909                Token::Str("token"),
910                Token::Str("interaction token"),
911                Token::StructEnd,
912            ],
913        );
914
915        Ok(())
916    }
917}