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