Skip to main content

serenity/model/
gateway.rs

1//! Models pertaining to the gateway.
2
3use std::num::NonZeroU16;
4
5use serde::ser::SerializeSeq;
6use url::Url;
7
8use super::prelude::*;
9use super::utils::*;
10
11/// A representation of the data retrieved from the bot gateway endpoint.
12///
13/// This is different from the [`Gateway`], as this includes the number of shards that Discord
14/// recommends to use for a bot user.
15///
16/// This is only applicable to bot users.
17///
18/// [Discord docs](https://discord.com/developers/docs/topics/gateway#get-gateway-bot-json-response).
19#[derive(Clone, Debug, Deserialize, Serialize)]
20#[non_exhaustive]
21pub struct BotGateway {
22    /// The gateway to connect to.
23    pub url: String,
24    /// The number of shards that is recommended to be used by the current bot user.
25    pub shards: u32,
26    /// Information describing how many gateway sessions you can initiate within a ratelimit
27    /// period.
28    pub session_start_limit: SessionStartLimit,
29}
30
31/// Representation of an activity that a [`User`] is performing.
32///
33/// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-structure).
34#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
35#[derive(Clone, Debug, Deserialize, Serialize)]
36#[non_exhaustive]
37pub struct Activity {
38    /// The ID of the application for the activity.
39    #[serde(deserialize_with = "deserialize_buggy_id")]
40    #[serde(default)]
41    pub application_id: Option<ApplicationId>,
42    /// Images for the presence and their texts.
43    pub assets: Option<ActivityAssets>,
44    /// What the user is doing.
45    pub details: Option<String>,
46    /// Activity flags describing what the payload includes.
47    pub flags: Option<ActivityFlags>,
48    /// Whether or not the activity is an instanced game session.
49    pub instance: Option<bool>,
50    /// The type of activity being performed
51    #[serde(rename = "type")]
52    pub kind: ActivityType,
53    /// The name of the activity.
54    pub name: String,
55    /// Information about the user's current party.
56    pub party: Option<ActivityParty>,
57    /// Secrets for Rich Presence joining and spectating.
58    pub secrets: Option<ActivitySecrets>,
59    /// The user's current party status.
60    pub state: Option<String>,
61    /// Emoji currently used in custom status
62    pub emoji: Option<ActivityEmoji>,
63    /// Unix timestamps for the start and/or end times of the activity.
64    pub timestamps: Option<ActivityTimestamps>,
65    /// The sync ID of the activity. Mainly used by the Spotify activity type which uses this
66    /// parameter to store the track ID.
67    #[cfg(feature = "unstable_discord_api")]
68    pub sync_id: Option<String>,
69    /// The session ID of the activity. Reserved for specific activity types, such as the Activity
70    /// that is transmitted when a user is listening to Spotify.
71    #[cfg(feature = "unstable_discord_api")]
72    pub session_id: Option<String>,
73    /// The Stream URL if [`Self::kind`] is [`ActivityType::Streaming`].
74    pub url: Option<Url>,
75    /// The buttons of this activity.
76    ///
77    /// **Note**: There can only be up to 2 buttons.
78    #[serde(default, deserialize_with = "deserialize_buttons")]
79    pub buttons: Vec<ActivityButton>,
80    /// Unix timestamp (in milliseconds) of when the activity was added to the user's session
81    pub created_at: u64,
82}
83
84/// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-buttons).
85#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
86#[derive(Clone, Debug, Serialize, Deserialize)]
87#[non_exhaustive]
88pub struct ActivityButton {
89    /// The text shown on the button.
90    pub label: String,
91    /// The url opened when clicking the button.
92    ///
93    /// **Note**: Bots cannot access activity button URL.
94    #[serde(default)]
95    pub url: String,
96}
97
98/// The assets for an activity.
99///
100/// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-assets).
101#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
102#[derive(Clone, Debug, Deserialize, Serialize)]
103#[non_exhaustive]
104pub struct ActivityAssets {
105    /// The ID for a large asset of the activity, usually a snowflake.
106    pub large_image: Option<String>,
107    /// Text displayed when hovering over the large image of the activity.
108    pub large_text: Option<String>,
109    /// The ID for a small asset of the activity, usually a snowflake.
110    pub small_image: Option<String>,
111    /// Text displayed when hovering over the small image of the activity.
112    pub small_text: Option<String>,
113}
114
115bitflags! {
116    /// A set of flags defining what is in an activity's payload.
117    ///
118    /// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-flags).
119    #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
120    #[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
121    pub struct ActivityFlags: u64 {
122        /// Whether the activity is an instance activity.
123        const INSTANCE = 1 << 0;
124        /// Whether the activity is joinable.
125        const JOIN = 1 << 1;
126        /// Whether the activity can be spectated.
127        const SPECTATE = 1 << 2;
128        /// Whether a request can be sent to join the user's party.
129        const JOIN_REQUEST = 1 << 3;
130        /// Whether the activity can be synced.
131        const SYNC = 1 << 4;
132        /// Whether the activity can be played.
133        const PLAY = 1 << 5;
134        /// Whether the activity party is friend only.
135        const PARTY_PRIVACY_FRIENDS = 1 << 6;
136        /// Whether the activity party is in a voice channel.
137        const PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7;
138        /// Whether the activity can be embedded.
139        const EMBEDDED = 1 << 8;
140    }
141}
142
143/// Information about an activity's party.
144///
145/// [Discord docs](https://discord.com/developers/docs/game-sdk/activities#data-models-activityparty-struct).
146#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
147#[derive(Clone, Debug, Deserialize, Serialize)]
148#[non_exhaustive]
149pub struct ActivityParty {
150    /// The ID of the party.
151    pub id: Option<String>,
152    /// Used to show the party's current and maximum size.
153    pub size: Option<[u32; 2]>,
154}
155
156/// Secrets for an activity.
157///
158/// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-secrets).
159#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
160#[derive(Clone, Debug, Deserialize, Serialize)]
161#[non_exhaustive]
162pub struct ActivitySecrets {
163    /// The secret for joining a party.
164    pub join: Option<String>,
165    /// The secret for a specific instanced match.
166    #[serde(rename = "match")]
167    pub match_: Option<String>,
168    /// The secret for spectating an activity.
169    pub spectate: Option<String>,
170}
171
172/// Representation of an emoji used in a custom status
173///
174/// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-emoji).
175#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
176#[derive(Clone, Debug, Deserialize, Serialize)]
177#[non_exhaustive]
178pub struct ActivityEmoji {
179    /// The name of the emoji.
180    pub name: String,
181    /// The id of the emoji.
182    pub id: Option<EmojiId>,
183    /// Whether this emoji is animated.
184    pub animated: Option<bool>,
185}
186
187enum_number! {
188    /// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types).
189    #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
190    #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
191    #[serde(from = "u8", into = "u8")]
192    #[non_exhaustive]
193    pub enum ActivityType {
194        /// An indicator that the user is playing a game.
195        #[default]
196        Playing = 0,
197        /// An indicator that the user is streaming to a service.
198        Streaming = 1,
199        /// An indicator that the user is listening to something.
200        Listening = 2,
201        /// An indicator that the user is watching something.
202        Watching = 3,
203        /// An indicator that the user uses custom statuses
204        Custom = 4,
205        /// An indicator that the user is competing somewhere.
206        Competing = 5,
207        _ => Unknown(u8),
208    }
209}
210
211/// A representation of the data retrieved from the gateway endpoint.
212///
213/// For the bot-specific gateway, refer to [`BotGateway`].
214///
215/// [Discord docs](https://discord.com/developers/docs/topics/gateway#get-gateway-example-response).
216#[derive(Clone, Debug, Deserialize, Serialize)]
217#[non_exhaustive]
218pub struct Gateway {
219    /// The gateway to connect to.
220    pub url: String,
221}
222
223/// Information detailing the current active status of a [`User`].
224///
225/// [Discord docs](https://discord.com/developers/docs/topics/gateway#client-status-object).
226#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
227#[derive(Clone, Debug, Deserialize, Serialize)]
228#[non_exhaustive]
229pub struct ClientStatus {
230    pub desktop: Option<OnlineStatus>,
231    pub mobile: Option<OnlineStatus>,
232    pub web: Option<OnlineStatus>,
233}
234
235/// Information about the user of a [`Presence`] event.
236///
237/// Fields should be identical to those of [`User`], except that every field but `id` is
238/// optional. This is currently not implemented fully.
239///
240/// [Discord docs](https://discord.com/developers/docs/resources/user#user-object),
241/// [modification description](https://discord.com/developers/docs/topics/gateway-events#presence-update).
242#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
243#[derive(Clone, Debug, Default, Deserialize, Serialize)]
244#[non_exhaustive]
245pub struct PresenceUser {
246    pub id: UserId,
247    #[serde(rename = "username")]
248    pub name: Option<String>,
249    #[serde(default, skip_serializing_if = "Option::is_none", with = "discriminator")]
250    pub discriminator: Option<NonZeroU16>,
251    pub global_name: Option<String>,
252    pub avatar: Option<ImageHash>,
253    #[serde(default)]
254    pub bot: Option<bool>,
255    #[serde(default)]
256    pub system: Option<bool>,
257    #[serde(default)]
258    pub mfa_enabled: Option<bool>,
259    pub banner: Option<ImageHash>,
260    #[serde(rename = "accent_color")]
261    pub accent_colour: Option<Colour>,
262    pub locale: Option<String>,
263    pub verified: Option<bool>,
264    pub email: Option<String>,
265    #[serde(default)]
266    pub flags: Option<UserPublicFlags>,
267    #[serde(default)]
268    pub premium_type: Option<PremiumType>,
269    pub public_flags: Option<UserPublicFlags>,
270    pub member: Option<Box<PartialMember>>,
271    pub primary_guild: Option<PrimaryGuild>,
272    pub avatar_decoration_data: Option<AvatarDecorationData>,
273    pub collectibles: Option<Collectibles>,
274    // TODO: should really go over these fields at some point and check them.
275}
276
277impl PresenceUser {
278    /// Attempts to convert this [`PresenceUser`] instance into a [`User`].
279    ///
280    /// If one of [`User`]'s required fields is None in `self`, None is returned.
281    #[must_use]
282    pub fn into_user(self) -> Option<User> {
283        Some(User {
284            avatar: self.avatar,
285            bot: self.bot?,
286            discriminator: self.discriminator,
287            global_name: self.global_name,
288            id: self.id,
289            name: self.name?,
290            public_flags: self.public_flags,
291            banner: self.banner,
292            accent_colour: self.accent_colour,
293            member: self.member,
294            system: false,
295            mfa_enabled: self.mfa_enabled.unwrap_or_default(),
296            locale: self.locale,
297            verified: self.verified,
298            email: self.email,
299            flags: self.public_flags.unwrap_or_default(),
300            premium_type: self.premium_type.unwrap_or_default(),
301            primary_guild: self.primary_guild,
302            avatar_decoration_data: self.avatar_decoration_data,
303            collectibles: self.collectibles,
304        })
305    }
306
307    /// Attempts to convert this [`PresenceUser`] instance into a [`User`].
308    ///
309    /// Will clone individual fields if needed.
310    ///
311    /// If one of [`User`]'s required fields is None in `self`, None is returned.
312    #[must_use]
313    pub fn to_user(&self) -> Option<User> {
314        self.clone().into_user()
315    }
316
317    #[cfg(feature = "cache")] // method is only used with the cache feature enabled
318    pub(crate) fn update_with_user(&mut self, user: &User) {
319        self.id = user.id;
320        if let Some(avatar) = user.avatar {
321            self.avatar = Some(avatar);
322        }
323        self.bot = Some(user.bot);
324        self.discriminator = user.discriminator;
325        self.name = Some(user.name.clone());
326        if let Some(public_flags) = user.public_flags {
327            self.public_flags = Some(public_flags);
328        }
329    }
330}
331
332/// Information detailing the current online status of a [`User`].
333///
334/// [Discord docs](https://discord.com/developers/docs/topics/gateway#presence-update-presence-update-event-fields).
335#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
336#[derive(Clone, Debug, Deserialize, Serialize)]
337#[non_exhaustive]
338pub struct Presence {
339    /// Data about the associated user.
340    pub user: PresenceUser,
341    /// The `GuildId` the presence update is coming from.
342    pub guild_id: Option<GuildId>,
343    /// The user's online status.
344    pub status: OnlineStatus,
345    /// [`User`]'s current activities.
346    #[serde(default)]
347    pub activities: Vec<Activity>,
348    /// The devices a user are currently active on, if available.
349    pub client_status: Option<ClientStatus>,
350}
351
352/// An initial set of information given after IDENTIFYing to the gateway.
353///
354/// [Discord docs](https://discord.com/developers/docs/topics/gateway#ready-ready-event-fields).
355#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
356#[derive(Clone, Debug, Deserialize, Serialize)]
357#[non_exhaustive]
358pub struct Ready {
359    /// API version
360    #[serde(rename = "v")]
361    pub version: u8,
362    /// Information about the user including email
363    pub user: CurrentUser,
364    /// Guilds the user is in
365    pub guilds: Vec<UnavailableGuild>,
366    /// Used for resuming connections
367    pub session_id: String,
368    /// Gateway URL for resuming connections
369    pub resume_gateway_url: String,
370    /// Shard information associated with this session, if sent when identifying
371    pub shard: Option<ShardInfo>,
372    /// Contains id and flags
373    pub application: PartialCurrentApplicationInfo,
374}
375
376/// Information describing how many gateway sessions you can initiate within a ratelimit period.
377///
378/// [Discord docs](https://discord.com/developers/docs/topics/gateway#session-start-limit-object-session-start-limit-structure).
379#[derive(Clone, Debug, Deserialize, Serialize)]
380#[non_exhaustive]
381pub struct SessionStartLimit {
382    /// The number of sessions that you can still initiate within the current ratelimit period.
383    pub remaining: u64,
384    /// The number of milliseconds until the ratelimit period resets.
385    pub reset_after: u64,
386    /// The total number of session starts within the ratelimit period allowed.
387    pub total: u64,
388    /// The number of identify requests allowed per 5 seconds.
389    pub max_concurrency: u64,
390}
391
392#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
393#[derive(Clone, Copy, Debug)]
394pub struct ShardInfo {
395    pub id: ShardId,
396    pub total: u32,
397}
398
399impl ShardInfo {
400    #[must_use]
401    pub(crate) fn new(id: ShardId, total: u32) -> Self {
402        Self {
403            id,
404            total,
405        }
406    }
407}
408
409impl<'de> serde::Deserialize<'de> for ShardInfo {
410    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
411        <(u32, u32)>::deserialize(deserializer).map(|(id, total)| ShardInfo {
412            id: ShardId(id),
413            total,
414        })
415    }
416}
417
418impl serde::Serialize for ShardInfo {
419    fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
420        let mut seq = serializer.serialize_seq(Some(2))?;
421        seq.serialize_element(&self.id.0)?;
422        seq.serialize_element(&self.total)?;
423        seq.end()
424    }
425}
426
427/// Timestamps of when a user started and/or is ending their activity.
428///
429/// [Discord docs](https://discord.com/developers/docs/game-sdk/activities#data-models-activitytimestamps-struct).
430#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
431#[derive(Clone, Debug, Deserialize, Serialize)]
432#[non_exhaustive]
433pub struct ActivityTimestamps {
434    pub end: Option<u64>,
435    pub start: Option<u64>,
436}
437
438bitflags! {
439    /// [Gateway Intents] will limit the events your bot will receive via the gateway. By default,
440    /// all intents except [Privileged Intents] are selected.
441    ///
442    /// # What are Intents
443    ///
444    /// A [gateway intent] sets the types of gateway events (e.g. member joins, guild integrations,
445    /// guild emoji updates, ...) the bot shall receive. Carefully picking the needed intents
446    /// greatly helps the bot to scale, as less intents will result in less events to be received
447    /// via the network from Discord and less processing needed for handling the data.
448    ///
449    /// # Privileged Intents
450    ///
451    /// The intents [`GatewayIntents::GUILD_PRESENCES`], [`GatewayIntents::GUILD_MEMBERS`] and
452    /// [`GatewayIntents::MESSAGE_CONTENT`] are [Privileged Intents]. They need to be enabled in
453    /// the *developer portal*.
454    ///
455    /// **Note**: Once the bot is in 100 guilds or more, [the bot must be verified] in order to use
456    /// privileged intents.
457    ///
458    /// [Discord docs](https://discord.com/developers/docs/topics/gateway#list-of-intents).
459    ///
460    /// [Gateway Intents]: https://discord.com/developers/docs/topics/gateway#gateway-intents
461    /// [Privileged Intents]: https://discord.com/developers/docs/topics/gateway#privileged-intents
462    /// [the bot must be verified]: https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting
463    #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
464    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
465    pub struct GatewayIntents: u64 {
466        /// Enables the following gateway events:
467        ///  - GUILD_CREATE
468        ///  - GUILD_UPDATE
469        ///  - GUILD_DELETE
470        ///  - GUILD_ROLE_CREATE
471        ///  - GUILD_ROLE_UPDATE
472        ///  - GUILD_ROLE_DELETE
473        ///  - CHANNEL_CREATE
474        ///  - CHANNEL_UPDATE
475        ///  - CHANNEL_DELETE
476        ///  - CHANNEL_PINS_UPDATE
477        ///  - THREAD_CREATE
478        ///  - THREAD_UPDATE
479        ///  - THREAD_DELETE
480        ///  - THREAD_LIST_SYNC
481        ///  - THREAD_MEMBER_UPDATE
482        ///  - THREAD_MEMBERS_UPDATE
483        ///  - STAGE_INSTANCE_CREATE
484        ///  - STAGE_INSTANCE_UPDATE
485        ///  - STAGE_INSTANCE_DELETE
486        ///
487        /// **Info:** The THREAD_MEMBERS_UPDATE event contains different data depending on which
488        /// intents are used. See [Discord's Docs](https://discord.com/developers/docs/topics/gateway-events#thread-members-update)
489        /// for more information.
490        const GUILDS = 1;
491        /// Enables the following gateway events:
492        /// - GUILD_MEMBER_ADD
493        /// - GUILD_MEMBER_UPDATE
494        /// - GUILD_MEMBER_REMOVE
495        /// - THREAD_MEMBERS_UPDATE
496        ///
497        /// **Info**: This intent is *privileged*. In order to use it, you must head to your
498        /// application in the Developer Portal and enable the toggle for *Privileged Intents*, as
499        /// well as enabling it in your code.
500        ///
501        /// **Info:** The THREAD_MEMBERS_UPDATE event contains different data depending on which
502        /// intents are used. See [Discord's Docs](https://discord.com/developers/docs/topics/gateway-events#thread-members-update)
503        /// for more information.
504        const GUILD_MEMBERS = 1 << 1;
505
506        /// Enables the following gateway events:
507        /// - GUILD_AUDIT_LOG_ENTRY_CREATE
508        /// - GUILD_BAN_ADD
509        /// - GUILD_BAN_REMOVE
510        const GUILD_MODERATION = 1 << 2;
511        /// Backwards compatibility with old gateway event name. Same as GUILD_MODERATION
512        #[deprecated = "Use [`Self::GUILD_MODERATION`] instead"]
513        const GUILD_BANS = 1 << 2;
514
515        /// Enables the following gateway events:
516        /// - GUILD_EMOJIS_UPDATE
517        /// - GUILD_STICKERS_UPDATE
518        const GUILD_EMOJIS_AND_STICKERS = 1 << 3;
519        /// Enables the following gateway events:
520        /// - GUILD_INTEGRATIONS_UPDATE
521        /// - INTEGRATION_CREATE
522        /// - INTEGRATION_UPDATE
523        /// - INTEGRATION_DELETE
524        const GUILD_INTEGRATIONS = 1 << 4;
525        /// Enables the following gateway event:
526        /// - WEBHOOKS_UPDATE
527        const GUILD_WEBHOOKS = 1 << 5;
528        /// Enables the following gateway events:
529        /// - INVITE_CREATE
530        /// - INVITE_DELETE
531        const GUILD_INVITES = 1 << 6;
532        /// Enables the following gateway event:
533        /// - VOICE_STATE_UPDATE
534        ///
535        /// **Note**: this intent is mandatory for `songbird` to function properly.
536        const GUILD_VOICE_STATES = 1 << 7;
537        /// Enables the following gateway event:
538        /// - PRESENCE_UPDATE
539        ///
540        /// **Info**: This intent is *privileged*. In order to use it, you must head to your
541        /// application in the Developer Portal and enable the toggle for *Privileged Intents*,
542        /// as well as enabling it in your code.
543        const GUILD_PRESENCES = 1 << 8;
544        /// Enables the following gateway events in guilds:
545        /// - MESSAGE_CREATE
546        /// - MESSAGE_UPDATE
547        /// - MESSAGE_DELETE
548        /// - MESSAGE_DELETE_BULK
549        const GUILD_MESSAGES = 1 << 9;
550        /// Enables the following gateway events in guilds:
551        /// - MESSAGE_REACTION_ADD
552        /// - MESSAGE_REACTION_REMOVE
553        /// - MESSAGE_REACTION_REMOVE_ALL
554        /// - MESSAGE_REACTION_REMOVE_EMOJI
555        const GUILD_MESSAGE_REACTIONS = 1 << 10;
556        /// Enable following gateway event:
557        /// - TYPING_START
558        const GUILD_MESSAGE_TYPING = 1 << 11;
559
560        /// Enables the following gateway events for direct messages:
561        /// - MESSAGE_CREATE
562        /// - MESSAGE_UPDATE
563        /// - MESSAGE_DELETE
564        /// - CHANNEL_PINS_UPDATE
565        const DIRECT_MESSAGES = 1 << 12;
566        /// Enable following gateway events for direct messages:
567        /// - MESSAGE_REACTION_ADD
568        /// - MESSAGE_REACTION_REMOVE
569        /// - MESSAGE_REACTION_REMOVE_ALL
570        /// - MESSAGE_REACTION_REMOVE_EMOJI
571        const DIRECT_MESSAGE_REACTIONS = 1 << 13;
572        /// Enables the following gateway events for direct messages:
573        /// - TYPING_START
574        const DIRECT_MESSAGE_TYPING = 1 << 14;
575
576        /// Enables receiving message content in gateway events
577        ///
578        /// See [Discord's Docs](https://discord.com/developers/docs/topics/gateway#message-content-intent) for more information
579        ///
580        /// **Info**: This intent is *privileged*. In order to use it, you must head to your
581        /// application in the Developer Portal and enable the toggle for *Privileged Intents*,
582        /// as well as enabling it in your code.
583        const MESSAGE_CONTENT = 1 << 15;
584
585        /// Enables the following gateway events:
586        /// - GUILD_SCHEDULED_EVENT_CREATE
587        /// - GUILD_SCHEDULED_EVENT_UPDATE
588        /// - GUILD_SCHEDULED_EVENT_DELETE
589        /// - GUILD_SCHEDULED_EVENT_USER_ADD
590        /// - GUILD_SCHEDULED_EVENT_USER_REMOVE
591        const GUILD_SCHEDULED_EVENTS = 1 << 16;
592        /// Enables the following gateway events:
593        /// - AUTO_MODERATION_RULE_CREATE
594        /// - AUTO_MODERATION_RULE_UPDATE
595        /// - AUTO_MODERATION_RULE_DELETE
596        const AUTO_MODERATION_CONFIGURATION = 1 << 20;
597        /// Enables the following gateway events:
598        /// - AUTO_MODERATION_ACTION_EXECUTION
599        const AUTO_MODERATION_EXECUTION = 1 << 21;
600
601        /// Enables the following gateway events for guilds:
602        /// - MESSAGE_POLL_VOTE_ADD
603        /// - MESSAGE_POLL_VOTE_REMOVE
604        const GUILD_MESSAGE_POLLS = 1 << 24;
605        /// Enables the following gateway events for direct messages:
606        /// - MESSAGE_POLL_VOTE_ADD
607        /// - MESSAGE_POLL_VOTE_REMOVE
608        const DIRECT_MESSAGE_POLLS = 1 << 25;
609    }
610}
611
612impl GatewayIntents {
613    /// Gets all of the intents that aren't considered privileged by Discord.
614    #[must_use]
615    pub const fn non_privileged() -> GatewayIntents {
616        // bitflags don't support const evaluation. Workaround.
617        // See: https://github.com/bitflags/bitflags/issues/180
618        Self::privileged().complement()
619    }
620
621    /// Gets all of the intents that are considered privileged by Discord.
622    /// Use of these intents will require explicitly whitelisting the bot.
623    #[must_use]
624    pub const fn privileged() -> GatewayIntents {
625        // bitflags don't support const evaluation. Workaround.
626        // See: https://github.com/bitflags/bitflags/issues/180
627        Self::GUILD_MEMBERS.union(Self::GUILD_PRESENCES).union(Self::MESSAGE_CONTENT)
628    }
629}
630
631#[cfg(feature = "model")]
632impl GatewayIntents {
633    /// Checks if any of the included intents are privileged.
634    #[must_use]
635    pub const fn is_privileged(self) -> bool {
636        self.intersects(Self::privileged())
637    }
638
639    /// Shorthand for checking that the set of intents contains the [GUILDS] intent.
640    ///
641    /// [GUILDS]: Self::GUILDS
642    #[must_use]
643    pub const fn guilds(self) -> bool {
644        self.contains(Self::GUILDS)
645    }
646
647    /// Shorthand for checking that the set of intents contains the [GUILD_MEMBERS] intent.
648    ///
649    /// [GUILD_MEMBERS]: Self::GUILD_MEMBERS
650    #[must_use]
651    pub const fn guild_members(self) -> bool {
652        self.contains(Self::GUILD_MEMBERS)
653    }
654
655    /// Shorthand for checking that the set of intents contains the [GUILD_BANS] intent.
656    ///
657    /// [GUILD_BANS]: Self::GUILD_BANS
658    ///
659    /// This is the same as calling guild_moderation since Discord changed the name
660    #[must_use]
661    #[deprecated = "Use [`Self::guild_moderation`] instead"]
662    pub const fn guild_bans(self) -> bool {
663        #[allow(deprecated)] // this is a deprecated method itself
664        self.contains(Self::GUILD_BANS)
665    }
666
667    /// Shorthand for checking that the set of intents contains the [GUILD_MODERATION] intent.
668    ///
669    /// [GUILD_MODERATION]: Self::GUILD_MODERATION
670    #[must_use]
671    pub const fn guild_moderation(self) -> bool {
672        self.contains(Self::GUILD_MODERATION)
673    }
674
675    /// Shorthand for checking that the set of intents contains the [GUILD_EMOJIS_AND_STICKERS]
676    /// intent.
677    ///
678    /// [GUILD_EMOJIS_AND_STICKERS]: Self::GUILD_EMOJIS_AND_STICKERS
679    #[must_use]
680    pub const fn guild_emojis_and_stickers(self) -> bool {
681        self.contains(Self::GUILD_EMOJIS_AND_STICKERS)
682    }
683
684    /// Shorthand for checking that the set of intents contains the [GUILD_INTEGRATIONS] intent.
685    ///
686    /// [GUILD_INTEGRATIONS]: Self::GUILD_INTEGRATIONS
687    #[must_use]
688    pub const fn guild_integrations(self) -> bool {
689        self.contains(Self::GUILD_INTEGRATIONS)
690    }
691
692    /// Shorthand for checking that the set of intents contains the [GUILD_WEBHOOKS] intent.
693    ///
694    /// [GUILD_WEBHOOKS]: Self::GUILD_WEBHOOKS
695    #[must_use]
696    pub const fn guild_webhooks(self) -> bool {
697        self.contains(Self::GUILD_WEBHOOKS)
698    }
699
700    /// Shorthand for checking that the set of intents contains the [GUILD_INVITES] intent.
701    ///
702    /// [GUILD_INVITES]: Self::GUILD_INVITES
703    #[must_use]
704    pub const fn guild_invites(self) -> bool {
705        self.contains(Self::GUILD_INVITES)
706    }
707
708    /// Shorthand for checking that the set of intents contains the [GUILD_VOICE_STATES] intent.
709    ///
710    /// [GUILD_VOICE_STATES]: Self::GUILD_VOICE_STATES
711    #[must_use]
712    pub const fn guild_voice_states(self) -> bool {
713        self.contains(Self::GUILD_VOICE_STATES)
714    }
715
716    /// Shorthand for checking that the set of intents contains the [GUILD_PRESENCES] intent.
717    ///
718    /// [GUILD_PRESENCES]: Self::GUILD_PRESENCES
719    #[must_use]
720    pub const fn guild_presences(self) -> bool {
721        self.contains(Self::GUILD_PRESENCES)
722    }
723
724    /// Shorthand for checking that the set of intents contains the [GUILD_MESSAGE_REACTIONS]
725    /// intent.
726    ///
727    /// [GUILD_MESSAGE_REACTIONS]: Self::GUILD_MESSAGE_REACTIONS
728    #[must_use]
729    pub const fn guild_message_reactions(self) -> bool {
730        self.contains(Self::GUILD_MESSAGE_REACTIONS)
731    }
732
733    /// Shorthand for checking that the set of intents contains the [GUILD_MESSAGE_TYPING] intent.
734    ///
735    /// [GUILD_MESSAGE_TYPING]: Self::GUILD_MESSAGE_TYPING
736    #[must_use]
737    pub const fn guild_message_typing(self) -> bool {
738        self.contains(Self::GUILD_MESSAGE_TYPING)
739    }
740
741    /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGES] intent.
742    ///
743    /// [DIRECT_MESSAGES]: Self::DIRECT_MESSAGES
744    #[must_use]
745    pub const fn direct_messages(self) -> bool {
746        self.contains(Self::DIRECT_MESSAGES)
747    }
748
749    /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGE_REACTIONS]
750    /// intent.
751    ///
752    /// [DIRECT_MESSAGE_REACTIONS]: Self::DIRECT_MESSAGE_REACTIONS
753    #[must_use]
754    pub const fn direct_message_reactions(self) -> bool {
755        self.contains(Self::DIRECT_MESSAGE_REACTIONS)
756    }
757
758    /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGE_TYPING] intent.
759    ///
760    /// [DIRECT_MESSAGE_TYPING]: Self::DIRECT_MESSAGE_TYPING
761    #[must_use]
762    pub const fn direct_message_typing(self) -> bool {
763        self.contains(Self::DIRECT_MESSAGE_TYPING)
764    }
765
766    /// Shorthand for checking that the set of intents contains the [MESSAGE_CONTENT] intent.
767    ///
768    /// [MESSAGE_CONTENT]: Self::MESSAGE_CONTENT
769    #[must_use]
770    pub const fn message_content(self) -> bool {
771        self.contains(Self::MESSAGE_CONTENT)
772    }
773
774    /// Shorthand for checking that the set of intents contains the [GUILD_SCHEDULED_EVENTS]
775    /// intent.
776    ///
777    /// [GUILD_SCHEDULED_EVENTS]: Self::GUILD_SCHEDULED_EVENTS
778    #[must_use]
779    pub const fn guild_scheduled_events(self) -> bool {
780        self.contains(Self::GUILD_SCHEDULED_EVENTS)
781    }
782
783    /// Shorthand for checking that the set of intents contains the [AUTO_MODERATION_CONFIGURATION]
784    /// intent.
785    ///
786    /// [AUTO_MODERATION_CONFIGURATION]: Self::AUTO_MODERATION_CONFIGURATION
787    #[must_use]
788    pub const fn auto_moderation_configuration(self) -> bool {
789        self.contains(Self::AUTO_MODERATION_CONFIGURATION)
790    }
791
792    /// Shorthand for checking that the set of intents contains the [AUTO_MODERATION_EXECUTION]
793    /// intent.
794    ///
795    /// [AUTO_MODERATION_EXECUTION]: Self::AUTO_MODERATION_EXECUTION
796    #[must_use]
797    pub const fn auto_moderation_execution(self) -> bool {
798        self.contains(Self::AUTO_MODERATION_EXECUTION)
799    }
800}
801
802impl Default for GatewayIntents {
803    fn default() -> Self {
804        Self::non_privileged()
805    }
806}