diff --git a/src/cache/event.rs b/src/cache/event.rs index ae803e6abaa..43fe739d3b1 100644 --- a/src/cache/event.rs +++ b/src/cache/event.rs @@ -18,7 +18,6 @@ use crate::model::event::{ GuildRoleDeleteEvent, GuildRoleUpdateEvent, GuildStickersUpdateEvent, - GuildUnavailableEvent, GuildUpdateEvent, MessageCreateEvent, MessageUpdateEvent, @@ -214,6 +213,13 @@ impl CacheUpdate for GuildDeleteEvent { type Output = Guild; fn update(&mut self, cache: &Cache) -> Option { + if self.guild.unavailable { + cache.unavailable_guilds.insert(self.guild.id); + cache.guilds.remove(&self.guild.id); + + return None; + } + match cache.guilds.remove(&self.guild.id) { Some(guild) => { for (channel_id, channel) in &guild.1.channels { @@ -397,17 +403,6 @@ impl CacheUpdate for GuildStickersUpdateEvent { } } -impl CacheUpdate for GuildUnavailableEvent { - type Output = (); - - fn update(&mut self, cache: &Cache) -> Option<()> { - cache.unavailable_guilds.insert(self.guild_id); - cache.guilds.remove(&self.guild_id); - - None - } -} - impl CacheUpdate for GuildUpdateEvent { type Output = (); diff --git a/src/cache/mod.rs b/src/cache/mod.rs index b90a4f5730c..7b36722c860 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -158,9 +158,8 @@ pub struct Cache { /// A map of channels in [`Guild`]s that the current user has received data /// for. /// - /// When a [`Event::GuildDelete`] or [`Event::GuildUnavailable`] is - /// received and processed by the cache, the relevant channels are also - /// removed from this map. + /// When a [`Event::GuildDelete`] is received and processed by the cache, + /// the relevant channels are also removed from this map. pub(crate) channels: DashMap, /// Cache of channels that have been fetched via to_channel. /// @@ -182,8 +181,7 @@ pub struct Cache { pub(crate) private_channels: DashMap, /// The total number of shards being used by the bot. pub(crate) shard_count: RwLock, - /// A list of guilds which are "unavailable". Refer to the documentation for - /// [`Event::GuildUnavailable`] for more information on when this can occur. + /// A list of guilds which are "unavailable". /// /// Additionally, guilds are always unavailable for bot users when a Ready /// is received. Guilds are "sent in" over time through the receiving of diff --git a/src/client/bridge/gateway/shard_runner.rs b/src/client/bridge/gateway/shard_runner.rs index ca89dd53358..d839634deda 100644 --- a/src/client/bridge/gateway/shard_runner.rs +++ b/src/client/bridge/gateway/shard_runner.rs @@ -5,7 +5,6 @@ use async_tungstenite::tungstenite; use async_tungstenite::tungstenite::error::Error as TungsteniteError; use async_tungstenite::tungstenite::protocol::frame::CloseFrame; use futures::channel::mpsc::{self, UnboundedReceiver as Receiver, UnboundedSender as Sender}; -use serde::Deserialize; use tokio::sync::RwLock; use tracing::{debug, error, info, instrument, trace, warn}; use typemap_rev::TypeMap; @@ -551,8 +550,7 @@ impl ShardRunner { #[instrument(skip(self))] async fn recv_event(&mut self) -> Result<(Option, Option, bool)> { let gw_event = match self.shard.client.recv_json().await { - Ok(Some(value)) => GatewayEvent::deserialize(value).map(Some).map_err(From::from), - Ok(None) => Ok(None), + Ok(inner) => Ok(inner), Err(Error::Tungstenite(TungsteniteError::Io(_))) => { debug!("Attempting to auto-reconnect"); diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs index ba75e6cfc1e..7c7c842e00a 100644 --- a/src/client/dispatch.rs +++ b/src/client/dispatch.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use futures::channel::mpsc::UnboundedSender as Sender; use futures::future::{BoxFuture, FutureExt}; use tokio::sync::RwLock; -use tracing::instrument; +use tracing::{instrument, warn}; use typemap_rev::TypeMap; #[cfg(feature = "gateway")] @@ -117,9 +117,6 @@ impl DispatchEvent { Self::Model(Event::GuildStickersUpdate(ref mut event)) => { update(cache_and_http, event); }, - Self::Model(Event::GuildUnavailable(ref mut event)) => { - update(cache_and_http, event); - }, // Already handled by the framework check macro Self::Model(Event::MessageCreate(_)) => {}, Self::Model(Event::MessageUpdate(ref mut event)) => { @@ -574,13 +571,6 @@ async fn handle_event( event_handler.guild_stickers_update(context, event.guild_id, event.stickers).await; }); }, - Event::GuildUnavailable(mut event) => { - update(&cache_and_http, &mut event); - - spawn_named("dispatch::event_handler::guild_unavailable", async move { - event_handler.guild_unavailable(context, event.guild_id).await; - }); - }, Event::GuildUpdate(mut event) => { spawn_named("dispatch::event_handler::guild_update", async move { feature_cache! {{ @@ -681,11 +671,7 @@ async fn handle_event( event_handler.typing_start(context, event).await; }); }, - Event::Unknown(event) => { - spawn_named("dispatch::event_handler::unknown", async move { - event_handler.unknown(context, event.kind, event.value).await; - }); - }, + Event::Unknown => warn!("An unknown event was received"), Event::UserUpdate(mut event) => { let _before = update(&cache_and_http, &mut event); diff --git a/src/client/event_handler.rs b/src/client/event_handler.rs index f85c6c44e5c..3d2a4bf4b80 100644 --- a/src/client/event_handler.rs +++ b/src/client/event_handler.rs @@ -4,7 +4,6 @@ use async_trait::async_trait; use super::context::Context; use crate::client::bridge::gateway::event::*; -use crate::json::Value; use crate::model::application::command::CommandPermission; use crate::model::application::interaction::Interaction; use crate::model::prelude::*; @@ -259,11 +258,6 @@ pub trait EventHandler: Send + Sync { ) { } - /// Dispatched when a guild became unavailable. - /// - /// Provides the guild's id. - async fn guild_unavailable(&self, _ctx: Context, _guild_id: GuildId) {} - /// Dispatched when the guild is updated. /// /// Provides the guild's old full data (if available) and the new, albeit partial data. @@ -390,11 +384,6 @@ pub trait EventHandler: Send + Sync { /// Dispatched when a user starts typing. async fn typing_start(&self, _ctx: Context, _: TypingStartEvent) {} - /// Dispatched when an unknown event was sent from discord. - /// - /// Provides the event's name and its unparsed data. - async fn unknown(&self, _ctx: Context, _name: String, _raw: Value) {} - /// Dispatched when the bot's data is updated. /// /// Provides the old and new data. diff --git a/src/gateway/ws.rs b/src/gateway/ws.rs index 872b7e1a535..b7067f6e2c0 100644 --- a/src/gateway/ws.rs +++ b/src/gateway/ws.rs @@ -16,6 +16,7 @@ use crate::client::bridge::gateway::ChunkGuildFilter; use crate::constants::{self, OpCode}; use crate::gateway::{CurrentPresence, GatewayError}; use crate::json::{from_str, json, to_string, Value}; +use crate::model::event::GatewayEvent; use crate::model::gateway::GatewayIntents; use crate::model::id::GuildId; use crate::{Error, Result}; @@ -38,7 +39,7 @@ impl WsClient { Ok(Self(stream)) } - pub(crate) async fn recv_json(&mut self) -> Result> { + pub(crate) async fn recv_json(&mut self) -> Result> { let message = match timeout(TIMEOUT, self.0.next()).await { Ok(Some(Ok(msg))) => msg, Ok(Some(Err(e))) => return Err(e.into()), diff --git a/src/model/event.rs b/src/model/event.rs index af99be71fbe..a0060b9e7b1 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -7,10 +7,17 @@ use std::fmt; use serde::de::{Error as DeError, IgnoredAny, MapAccess}; use super::prelude::*; -use super::utils::{emojis, roles, stickers}; +use super::utils::{ + deserialize_val, + emojis, + ignore_input, + remove_from_map, + remove_from_map_opt, + roles, + stickers, +}; use crate::constants::OpCode; use crate::internal::prelude::*; -use crate::json::prelude::*; use crate::model::application::command::CommandPermission; use crate::model::application::interaction::Interaction; @@ -304,13 +311,6 @@ pub struct InviteDeleteEvent { pub code: String, } -#[derive(Clone, Debug, Deserialize, Serialize)] -#[non_exhaustive] -pub struct GuildUnavailableEvent { - #[serde(rename = "id")] - pub guild_id: GuildId, -} - #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(transparent)] #[non_exhaustive] @@ -637,73 +637,30 @@ pub enum GatewayEvent { impl<'de> Deserialize<'de> for GatewayEvent { fn deserialize>(deserializer: D) -> StdResult { - let mut map = JsonMap::deserialize(deserializer)?; - - let op = map - .remove("op") - .ok_or_else(|| DeError::custom("expected op")) - .and_then(OpCode::deserialize) - .map_err(DeError::custom)?; - - Ok(match op { - OpCode::Event => { - let s = map - .remove("s") - .ok_or_else(|| DeError::custom("expected gateway event sequence")) - .and_then(u64::deserialize) - .map_err(DeError::custom)?; - let kind = map - .remove("t") - .ok_or_else(|| DeError::custom("expected gateway event type")) - .and_then(EventType::deserialize) - .map_err(DeError::custom)?; - let payload = map - .remove("d") - .ok_or_else(|| Error::Decode("expected gateway event d", Value::from(map))) - .map_err(DeError::custom)?; - - let x = match deserialize_event_with_type(kind.clone(), payload) { - Ok(x) => x, - Err(why) => { - return Err(DeError::custom(format_args!("event {:?}: {}", kind, why))); - }, - }; - - GatewayEvent::Dispatch(s, x) - }, - OpCode::Heartbeat => { - let s = map - .remove("s") - .ok_or_else(|| DeError::custom("Expected heartbeat s")) - .and_then(u64::deserialize) - .map_err(DeError::custom)?; + let mut value = Value::deserialize(deserializer)?; + let map = value.as_object_mut().ok_or_else(|| DeError::custom("expected JsonMap"))?; - GatewayEvent::Heartbeat(s) - }, - OpCode::Reconnect => GatewayEvent::Reconnect, - OpCode::InvalidSession => { - let resumable = map - .remove("d") - .ok_or_else(|| DeError::custom("expected gateway invalid session d")) - .and_then(bool::deserialize) - .map_err(DeError::custom)?; - - GatewayEvent::InvalidateSession(resumable) + let seq = remove_from_map_opt(map, "s")?.flatten(); + + Ok(match remove_from_map(map, "op")? { + OpCode::Event => Self::Dispatch( + seq.ok_or_else(|| DeError::missing_field("s"))?, + deserialize_val(value)?, + ), + OpCode::Heartbeat => { + GatewayEvent::Heartbeat(seq.ok_or_else(|| DeError::missing_field("s"))?) }, + OpCode::InvalidSession => GatewayEvent::InvalidateSession(remove_from_map(map, "d")?), OpCode::Hello => { - let mut d = map - .remove("d") - .ok_or_else(|| DeError::custom("expected gateway hello d")) - .and_then(JsonMap::deserialize) - .map_err(DeError::custom)?; - let interval = d - .remove("heartbeat_interval") - .ok_or_else(|| DeError::custom("expected gateway hello interval")) - .and_then(u64::deserialize) - .map_err(DeError::custom)?; - - GatewayEvent::Hello(interval) + #[derive(Deserialize)] + struct HelloPayload { + heartbeat_interval: u64, + } + + let inner: HelloPayload = remove_from_map(map, "d")?; + GatewayEvent::Hello(inner.heartbeat_interval) }, + OpCode::Reconnect => GatewayEvent::Reconnect, OpCode::HeartbeatAck => GatewayEvent::HeartbeatAck, _ => return Err(DeError::custom("invalid opcode")), }) @@ -713,8 +670,9 @@ impl<'de> Deserialize<'de> for GatewayEvent { /// Event received over a websocket connection #[allow(clippy::large_enum_variant)] #[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[serde(tag = "t", content = "d")] #[non_exhaustive] -#[serde(untagged)] pub enum Event { /// The permissions of an [`Command`] was changed. /// @@ -763,8 +721,6 @@ pub enum Event { GuildRoleUpdate(GuildRoleUpdateEvent), /// A [`Sticker`] was created, updated, or deleted GuildStickersUpdate(GuildStickersUpdateEvent), - /// When a guild is unavailable, such as due to a Discord server outage. - GuildUnavailable(GuildUnavailableEvent), GuildUpdate(GuildUpdateEvent), /// An [`Invite`] was created. /// @@ -862,7 +818,8 @@ pub enum Event { /// A guild member has unsubscribed from a scheduled event. GuildScheduledEventUserRemove(GuildScheduledEventUserRemoveEvent), /// An event type not covered by the above - Unknown(UnknownEvent), + #[serde(other, deserialize_with = "ignore_input")] + Unknown, } #[cfg(feature = "model")] @@ -1020,12 +977,6 @@ macro_rules! with_related_ids_for_event_types { channel_id: Never, message_id: Never, }, - Self::GuildUnavailable, Self::GuildUnavailable(e) => { - user_id: Never, - guild_id: Some(e.guild_id), - channel_id: Never, - message_id: Never, - }, Self::GuildUpdate, Self::GuildUpdate(e) => { user_id: Never, guild_id: Some(e.guild.id), @@ -1269,7 +1220,7 @@ macro_rules! define_event_related_id_methods { use RelatedId::*; #[allow(unused_variables)] match self { - Self::Unknown(_) => Never, + Self::Unknown => Never, $( $(#[$attr])? $variant => $user_id @@ -1283,7 +1234,7 @@ macro_rules! define_event_related_id_methods { use RelatedId::*; #[allow(unused_variables)] match self { - Self::Unknown(_) => Never, + Self::Unknown => Never, $( $(#[$attr])? $variant => $guild_id @@ -1297,7 +1248,7 @@ macro_rules! define_event_related_id_methods { use RelatedId::*; #[allow(unused_variables)] match self { - Self::Unknown(_) => Never, + Self::Unknown => Never, $( $(#[$attr])? $variant => $channel_id @@ -1311,7 +1262,7 @@ macro_rules! define_event_related_id_methods { use RelatedId::*; #[allow(unused_variables)] match self { - Self::Unknown(_) => Never, + Self::Unknown => Never, $( $(#[$attr])? $variant => $message_id @@ -1347,7 +1298,6 @@ impl Event { Self::GuildRoleDelete(_) => EventType::GuildRoleDelete, Self::GuildRoleUpdate(_) => EventType::GuildRoleUpdate, Self::GuildStickersUpdate(_) => EventType::GuildStickersUpdate, - Self::GuildUnavailable(_) => EventType::GuildUnavailable, Self::GuildUpdate(_) => EventType::GuildUpdate, Self::InviteCreate(_) => EventType::InviteCreate, Self::InviteDelete(_) => EventType::InviteDelete, @@ -1385,7 +1335,7 @@ impl Event { Self::GuildScheduledEventDelete(_) => EventType::GuildScheduledEventDelete, Self::GuildScheduledEventUserAdd(_) => EventType::GuildScheduledEventUserAdd, Self::GuildScheduledEventUserRemove(_) => EventType::GuildScheduledEventUserRemove, - Self::Unknown(unknown) => EventType::Other(unknown.kind.clone()), + Self::Unknown => EventType::Other, } } @@ -1440,105 +1390,6 @@ impl TryFrom> for Option { } } -/// Deserializes a [`serde_json::Value`] into an [`Event`]. -/// -/// The given [`EventType`] is used to determine what event to deserialize into. -/// For example, an [`EventType::ChannelCreate`] will cause the given value to -/// attempt to be deserialized into a [`ChannelCreateEvent`]. -/// -/// Special handling is done in regards to [`EventType::GuildCreate`] and -/// [`EventType::GuildDelete`]: they check for an `"unavailable"` key and, if -/// present and containing a value of `true`, will cause a -/// [`GuildUnavailableEvent`] to be returned. Otherwise, all other event types -/// correlate to the deserialization of their appropriate event. -/// -/// # Errors -/// -/// Returns [`Error::Json`] if there is an error in deserializing the event data. -pub fn deserialize_event_with_type(kind: EventType, v: Value) -> Result { - Ok(match kind { - EventType::ApplicationCommandPermissionsUpdate => { - Event::ApplicationCommandPermissionsUpdate(from_value(v)?) - }, - EventType::ChannelCreate => Event::ChannelCreate(from_value(v)?), - EventType::ChannelDelete => Event::ChannelDelete(from_value(v)?), - EventType::ChannelPinsUpdate => Event::ChannelPinsUpdate(from_value(v)?), - EventType::ChannelUpdate => Event::ChannelUpdate(from_value(v)?), - EventType::GuildBanAdd => Event::GuildBanAdd(from_value(v)?), - EventType::GuildBanRemove => Event::GuildBanRemove(from_value(v)?), - EventType::GuildCreate | EventType::GuildUnavailable => { - // GuildUnavailable isn't actually received from the gateway, so it - // can be lumped in with GuildCreate's arm. - - if v.get("unavailable").and_then(Value::as_bool).unwrap_or(false) { - Event::GuildUnavailable(from_value(v)?) - } else { - Event::GuildCreate(from_value(v)?) - } - }, - EventType::GuildDelete => { - if v.get("unavailable").and_then(Value::as_bool).unwrap_or(false) { - Event::GuildUnavailable(from_value(v)?) - } else { - Event::GuildDelete(from_value(v)?) - } - }, - EventType::GuildEmojisUpdate => Event::GuildEmojisUpdate(from_value(v)?), - EventType::GuildIntegrationsUpdate => Event::GuildIntegrationsUpdate(from_value(v)?), - EventType::GuildMemberAdd => Event::GuildMemberAdd(from_value(v)?), - EventType::GuildMemberRemove => Event::GuildMemberRemove(from_value(v)?), - EventType::GuildMemberUpdate => Event::GuildMemberUpdate(from_value(v)?), - EventType::GuildMembersChunk => Event::GuildMembersChunk(from_value(v)?), - EventType::GuildRoleCreate => Event::GuildRoleCreate(from_value(v)?), - EventType::GuildRoleDelete => Event::GuildRoleDelete(from_value(v)?), - EventType::GuildRoleUpdate => Event::GuildRoleUpdate(from_value(v)?), - EventType::GuildStickersUpdate => Event::GuildStickersUpdate(from_value(v)?), - EventType::InviteCreate => Event::InviteCreate(from_value(v)?), - EventType::InviteDelete => Event::InviteDelete(from_value(v)?), - EventType::GuildUpdate => Event::GuildUpdate(from_value(v)?), - EventType::MessageCreate => Event::MessageCreate(from_value(v)?), - EventType::MessageDelete => Event::MessageDelete(from_value(v)?), - EventType::MessageDeleteBulk => Event::MessageDeleteBulk(from_value(v)?), - EventType::ReactionAdd => Event::ReactionAdd(from_value(v)?), - EventType::ReactionRemove => Event::ReactionRemove(from_value(v)?), - EventType::ReactionRemoveAll => Event::ReactionRemoveAll(from_value(v)?), - EventType::MessageUpdate => Event::MessageUpdate(from_value(v)?), - EventType::PresenceUpdate => Event::PresenceUpdate(from_value(v)?), - EventType::PresencesReplace => Event::PresencesReplace(from_value(v)?), - EventType::Ready => Event::Ready(from_value(v)?), - EventType::Resumed => Event::Resumed(from_value(v)?), - EventType::TypingStart => Event::TypingStart(from_value(v)?), - EventType::UserUpdate => Event::UserUpdate(from_value(v)?), - EventType::VoiceServerUpdate => Event::VoiceServerUpdate(from_value(v)?), - EventType::VoiceStateUpdate => Event::VoiceStateUpdate(from_value(v)?), - EventType::WebhookUpdate => Event::WebhookUpdate(from_value(v)?), - EventType::InteractionCreate => Event::InteractionCreate(from_value(v)?), - EventType::IntegrationCreate => Event::IntegrationCreate(from_value(v)?), - EventType::IntegrationUpdate => Event::IntegrationUpdate(from_value(v)?), - EventType::IntegrationDelete => Event::IntegrationDelete(from_value(v)?), - EventType::StageInstanceCreate => Event::StageInstanceCreate(from_value(v)?), - EventType::StageInstanceUpdate => Event::StageInstanceUpdate(from_value(v)?), - EventType::StageInstanceDelete => Event::StageInstanceDelete(from_value(v)?), - EventType::ThreadCreate => Event::ThreadCreate(from_value(v)?), - EventType::ThreadUpdate => Event::ThreadUpdate(from_value(v)?), - EventType::ThreadDelete => Event::ThreadDelete(from_value(v)?), - EventType::ThreadListSync => Event::ThreadListSync(from_value(v)?), - EventType::ThreadMemberUpdate => Event::ThreadMemberUpdate(from_value(v)?), - EventType::ThreadMembersUpdate => Event::ThreadMembersUpdate(from_value(v)?), - EventType::GuildScheduledEventCreate => Event::GuildScheduledEventCreate(from_value(v)?), - EventType::GuildScheduledEventUpdate => Event::GuildScheduledEventUpdate(from_value(v)?), - EventType::GuildScheduledEventDelete => Event::GuildScheduledEventDelete(from_value(v)?), - EventType::GuildScheduledEventUserAdd => Event::GuildScheduledEventUserAdd(from_value(v)?), - EventType::GuildScheduledEventUserRemove => { - Event::GuildScheduledEventUserRemove(from_value(v)?) - }, - EventType::Other(kind) => Event::Unknown(UnknownEvent { - kind, - value: v, - }), - }) -} - /// The type of event dispatch received from the gateway. /// /// This is useful for deciding how to deserialize a received payload. @@ -1625,10 +1476,6 @@ pub enum EventType { /// /// This maps to [`GuildStickersUpdateEvent`]. GuildStickersUpdate, - /// Indicator that a guild unavailable payload was received. - /// - /// This maps to [`GuildUnavailableEvent`]. - GuildUnavailable, /// Indicator that a guild update payload was received. /// /// This maps to [`GuildUpdateEvent`]. @@ -1779,10 +1626,7 @@ pub enum EventType { /// This maps to [`GuildScheduledEventUserRemoveEvent`]. GuildScheduledEventUserRemove, /// An unknown event was received over the gateway. - /// - /// This should be logged so that support for it can be added in the - /// library. - Other(String), + Other, } impl From<&Event> for EventType { @@ -1814,7 +1658,7 @@ macro_rules! define_related_ids_for_event_type { #[must_use] pub fn related_ids(&self) -> RelatedIdsForEventType { match self { - Self::Other(_) => Default::default(), + Self::Other => Default::default(), $( $(#[$attr])? $variant => @@ -1965,100 +1809,9 @@ impl EventType { Self::GuildScheduledEventDelete => Some(Self::GUILD_SCHEDULED_EVENT_DELETE), Self::GuildScheduledEventUserAdd => Some(Self::GUILD_SCHEDULED_EVENT_USER_ADD), Self::GuildScheduledEventUserRemove => Some(Self::GUILD_SCHEDULED_EVENT_USER_REMOVE), - // GuildUnavailable is a synthetic event type, corresponding to either - // `GUILD_CREATE` or `GUILD_DELETE`, but we don't have enough information - // to recover the name here, so we return `None` instead. - Self::GuildUnavailable => None, - Self::Other(other) => Some(other), + Self::Other => None, } } with_related_ids_for_event_types!(define_related_ids_for_event_type); } - -impl<'de> Deserialize<'de> for EventType { - fn deserialize(deserializer: D) -> StdResult - where - D: Deserializer<'de>, - { - struct EventTypeVisitor; - - impl<'de> Visitor<'de> for EventTypeVisitor { - type Value = EventType; - - fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("event type str") - } - - fn visit_str(self, v: &str) -> StdResult - where - E: DeError, - { - Ok(match v { - EventType::APPLICATION_COMMAND_PERMISSIONS_UPDATE => { - EventType::ApplicationCommandPermissionsUpdate - }, - EventType::CHANNEL_CREATE => EventType::ChannelCreate, - EventType::CHANNEL_DELETE => EventType::ChannelDelete, - EventType::CHANNEL_PINS_UPDATE => EventType::ChannelPinsUpdate, - EventType::CHANNEL_UPDATE => EventType::ChannelUpdate, - EventType::GUILD_BAN_ADD => EventType::GuildBanAdd, - EventType::GUILD_BAN_REMOVE => EventType::GuildBanRemove, - EventType::GUILD_CREATE => EventType::GuildCreate, - EventType::GUILD_DELETE => EventType::GuildDelete, - EventType::GUILD_EMOJIS_UPDATE => EventType::GuildEmojisUpdate, - EventType::GUILD_INTEGRATIONS_UPDATE => EventType::GuildIntegrationsUpdate, - EventType::GUILD_MEMBER_ADD => EventType::GuildMemberAdd, - EventType::GUILD_MEMBER_REMOVE => EventType::GuildMemberRemove, - EventType::GUILD_MEMBER_UPDATE => EventType::GuildMemberUpdate, - EventType::GUILD_MEMBERS_CHUNK => EventType::GuildMembersChunk, - EventType::GUILD_ROLE_CREATE => EventType::GuildRoleCreate, - EventType::GUILD_ROLE_DELETE => EventType::GuildRoleDelete, - EventType::GUILD_ROLE_UPDATE => EventType::GuildRoleUpdate, - EventType::GUILD_STICKERS_UPDATE => EventType::GuildStickersUpdate, - EventType::INVITE_CREATE => EventType::InviteCreate, - EventType::INVITE_DELETE => EventType::InviteDelete, - EventType::GUILD_UPDATE => EventType::GuildUpdate, - EventType::MESSAGE_CREATE => EventType::MessageCreate, - EventType::MESSAGE_DELETE => EventType::MessageDelete, - EventType::MESSAGE_DELETE_BULK => EventType::MessageDeleteBulk, - EventType::MESSAGE_REACTION_ADD => EventType::ReactionAdd, - EventType::MESSAGE_REACTION_REMOVE => EventType::ReactionRemove, - EventType::MESSAGE_REACTION_REMOVE_ALL => EventType::ReactionRemoveAll, - EventType::MESSAGE_UPDATE => EventType::MessageUpdate, - EventType::PRESENCE_UPDATE => EventType::PresenceUpdate, - EventType::PRESENCES_REPLACE => EventType::PresencesReplace, - EventType::READY => EventType::Ready, - EventType::RESUMED => EventType::Resumed, - EventType::TYPING_START => EventType::TypingStart, - EventType::USER_UPDATE => EventType::UserUpdate, - EventType::VOICE_SERVER_UPDATE => EventType::VoiceServerUpdate, - EventType::VOICE_STATE_UPDATE => EventType::VoiceStateUpdate, - EventType::WEBHOOKS_UPDATE => EventType::WebhookUpdate, - EventType::INTERACTION_CREATE => EventType::InteractionCreate, - EventType::INTEGRATION_CREATE => EventType::IntegrationCreate, - EventType::INTEGRATION_UPDATE => EventType::IntegrationUpdate, - EventType::INTEGRATION_DELETE => EventType::IntegrationDelete, - EventType::STAGE_INSTANCE_CREATE => EventType::StageInstanceCreate, - EventType::STAGE_INSTANCE_UPDATE => EventType::StageInstanceUpdate, - EventType::STAGE_INSTANCE_DELETE => EventType::StageInstanceDelete, - EventType::THREAD_CREATE => EventType::ThreadCreate, - EventType::THREAD_UPDATE => EventType::ThreadUpdate, - EventType::THREAD_DELETE => EventType::ThreadDelete, - EventType::GUILD_SCHEDULED_EVENT_CREATE => EventType::GuildScheduledEventCreate, - EventType::GUILD_SCHEDULED_EVENT_UPDATE => EventType::GuildScheduledEventUpdate, - EventType::GUILD_SCHEDULED_EVENT_DELETE => EventType::GuildScheduledEventDelete, - EventType::GUILD_SCHEDULED_EVENT_USER_ADD => { - EventType::GuildScheduledEventUserAdd - }, - EventType::GUILD_SCHEDULED_EVENT_USER_REMOVE => { - EventType::GuildScheduledEventUserRemove - }, - other => EventType::Other(other.to_owned()), - }) - } - } - - deserializer.deserialize_str(EventTypeVisitor) - } -} diff --git a/src/model/utils.rs b/src/model/utils.rs index 508112e97cc..20d80f97b98 100644 --- a/src/model/utils.rs +++ b/src/model/utils.rs @@ -29,6 +29,35 @@ pub fn is_false(v: &bool) -> bool { !v } +#[allow(clippy::unnecessary_wraps)] +pub fn ignore_input<'de, D: Deserializer<'de>>(_: D) -> StdResult<(), D::Error> { + Ok(()) +} + +pub fn deserialize_val(val: Value) -> StdResult +where + T: serde::de::DeserializeOwned, + E: serde::de::Error, +{ + T::deserialize(val).map_err(serde::de::Error::custom) +} + +pub fn remove_from_map_opt(map: &mut JsonMap, key: &str) -> StdResult, E> +where + T: serde::de::DeserializeOwned, + E: serde::de::Error, +{ + map.remove(key).map(deserialize_val).transpose() +} + +pub fn remove_from_map(map: &mut JsonMap, key: &'static str) -> StdResult +where + T: serde::de::DeserializeOwned, + E: serde::de::Error, +{ + remove_from_map_opt(map, key)?.ok_or_else(|| serde::de::Error::missing_field(key)) +} + /// Used with `#[serde(with = "emojis")]` pub mod emojis { use std::collections::HashMap;