Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use #[serde(remote = "Self")] to simplify serde impls #2287

Merged
merged 1 commit into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 13 additions & 28 deletions src/model/application/interaction/application_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::client::Context;
use crate::http::Http;
use crate::internal::prelude::*;
use crate::model::application::command::{CommandOptionType, CommandType};
use crate::model::application::interaction::add_guild_id_to_resolved;
use crate::model::channel::{Attachment, Message, PartialChannel};
use crate::model::guild::{Member, PartialMember, Role};
use crate::model::id::{
Expand All @@ -36,13 +35,13 @@ use crate::model::id::{
UserId,
};
use crate::model::user::User;
use crate::model::utils::{remove_from_map, remove_from_map_opt};
use crate::model::Permissions;

/// An interaction when a user invokes a slash command.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object).
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Self")]
#[non_exhaustive]
pub struct CommandInteraction {
/// Id of the interaction.
Expand Down Expand Up @@ -238,35 +237,20 @@ impl CommandInteraction {
}
}

// Manual impl needed to insert guild_id into resolved Role's
impl<'de> Deserialize<'de> for CommandInteraction {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;

let guild_id = remove_from_map_opt::<GuildId, _>(&mut map, "guild_id")?;

if let Some(guild_id) = guild_id {
add_guild_id_to_resolved(&mut map, guild_id);
let mut interaction = Self::deserialize(deserializer)?; // calls #[serde(remote)]-generated inherent method
if let Some(guild_id) = interaction.guild_id {
interaction.data.resolved.roles.values_mut().for_each(|r| r.guild_id = guild_id);
}
Ok(interaction)
}
}

let member = remove_from_map_opt::<Box<Member>, _>(&mut map, "member")?;
let user = remove_from_map_opt(&mut map, "user")?
.or_else(|| member.as_ref().map(|m| m.user.clone()))
.ok_or_else(|| DeError::custom("expected user or member"))?;

Ok(Self {
guild_id,
member,
user,
id: remove_from_map(&mut map, "id")?,
application_id: remove_from_map(&mut map, "application_id")?,
data: remove_from_map(&mut map, "data")?,
channel_id: remove_from_map(&mut map, "channel_id")?,
token: remove_from_map(&mut map, "token")?,
version: remove_from_map(&mut map, "version")?,
app_permissions: remove_from_map_opt(&mut map, "app_permissions")?,
locale: remove_from_map(&mut map, "locale")?,
guild_locale: remove_from_map_opt(&mut map, "guild_locale")?,
})
impl Serialize for CommandInteraction {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
Self::serialize(self, serializer) // calls #[serde(remote)]-generated inherent method
}
}

Expand Down Expand Up @@ -622,6 +606,7 @@ fn option_to_raw(option: &CommandDataOption) -> StdResult<RawCommandDataOption,
Ok(raw)
}

// Manual impl needed to emulate integer enum tags
impl<'de> Deserialize<'de> for CommandDataOption {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
option_from_raw(RawCommandDataOption::deserialize(deserializer)?)
Expand Down
44 changes: 15 additions & 29 deletions src/model/application/interaction/message_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use crate::client::Context;
use crate::http::Http;
use crate::internal::prelude::*;
use crate::model::application::component::ComponentType;
use crate::model::application::interaction::add_guild_id_to_resolved;
use crate::model::channel::Message;
use crate::model::guild::Member;
#[cfg(feature = "model")]
Expand All @@ -30,13 +29,13 @@ use crate::model::id::{
UserId,
};
use crate::model::user::User;
use crate::model::utils::{remove_from_map, remove_from_map_opt};
use crate::model::Permissions;

/// An interaction triggered by a message component.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-structure).
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Self")]
#[non_exhaustive]
pub struct ComponentInteraction {
/// Id of the interaction.
Expand Down Expand Up @@ -217,36 +216,22 @@ impl ComponentInteraction {
}
}

// Manual impl needed to insert guild_id into model data
impl<'de> Deserialize<'de> for ComponentInteraction {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;

let guild_id = remove_from_map_opt(&mut map, "guild_id")?;

if let Some(guild_id) = guild_id {
add_guild_id_to_resolved(&mut map, guild_id);
let mut interaction = Self::deserialize(deserializer)?; // calls #[serde(remote)]-generated inherent method
if let (Some(guild_id), Some(member)) = (interaction.guild_id, &mut interaction.member) {
member.guild_id = guild_id;
// If `member` is present, `user` wasn't sent and is still filled with default data
interaction.user = member.user.clone();
}
Ok(interaction)
}
}

let member = remove_from_map_opt::<Member, _>(&mut map, "member")?;
let user = remove_from_map_opt(&mut map, "user")?
.or_else(|| member.as_ref().map(|m| m.user.clone()))
.ok_or_else(|| DeError::custom("expected user or member"))?;

Ok(Self {
guild_id,
member,
user,
id: remove_from_map(&mut map, "id")?,
application_id: remove_from_map(&mut map, "application_id")?,
data: remove_from_map(&mut map, "data")?,
channel_id: remove_from_map(&mut map, "channel_id")?,
token: remove_from_map(&mut map, "token")?,
version: remove_from_map(&mut map, "version")?,
message: remove_from_map(&mut map, "message")?,
app_permissions: remove_from_map_opt(&mut map, "app_permissions")?,
locale: remove_from_map(&mut map, "locale")?,
guild_locale: remove_from_map_opt(&mut map, "guild_locale")?,
})
impl Serialize for ComponentInteraction {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
Self::serialize(self, serializer) // calls #[serde(remote)]-generated inherent method
}
}

Expand All @@ -261,6 +246,7 @@ pub enum ComponentInteractionDataKind {
Unknown(u8),
}

// Manual impl needed to emulate integer enum tags
impl<'de> Deserialize<'de> for ComponentInteractionDataKind {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
#[derive(Deserialize)]
Expand Down
23 changes: 2 additions & 21 deletions src/model/application/interaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use self::ping::PingInteraction;
use crate::internal::prelude::*;
use crate::json::from_value;
use crate::model::guild::PartialMember;
use crate::model::id::{ApplicationId, GuildId, InteractionId};
use crate::model::id::{ApplicationId, InteractionId};
use crate::model::user::User;
use crate::model::utils::deserialize_val;
use crate::model::Permissions;
Expand Down Expand Up @@ -217,6 +217,7 @@ impl Interaction {
}
}

// Manual impl needed to emulate integer enum tags
impl<'de> Deserialize<'de> for Interaction {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
let map = JsonMap::deserialize(deserializer)?;
Expand Down Expand Up @@ -302,23 +303,3 @@ pub struct MessageInteraction {
#[serde(skip_serializing_if = "Option::is_none")]
pub member: Option<PartialMember>,
}

fn add_guild_id_to_resolved(map: &mut JsonMap, guild_id: GuildId) {
if let Some(member) = map.get_mut("member").and_then(Value::as_object_mut) {
member.insert("guild_id".to_string(), guild_id.get().into());
}

if let Some(data) = map.get_mut("data") {
if let Some(resolved) = data.get_mut("resolved") {
if let Some(roles) = resolved.get_mut("roles") {
if let Some(values) = roles.as_object_mut() {
for value in values.values_mut() {
if let Some(role) = value.as_object_mut() {
role.insert("guild_id".to_string(), guild_id.get().into());
};
}
}
}
}
}
}
44 changes: 15 additions & 29 deletions src/model/application/interaction/modal.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::de::{Deserialize, Deserializer};
use serde::Serialize;

use super::add_guild_id_to_resolved;
#[cfg(feature = "model")]
use crate::builder::{
CreateInteractionResponse,
Expand All @@ -18,13 +17,13 @@ use crate::model::guild::Member;
use crate::model::id::MessageId;
use crate::model::id::{ApplicationId, ChannelId, GuildId, InteractionId};
use crate::model::user::User;
use crate::model::utils::{remove_from_map, remove_from_map_opt};
use crate::model::Permissions;

/// An interaction triggered by a modal submit.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object).
#[derive(Clone, Debug, Serialize)]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(remote = "Self")]
#[non_exhaustive]
pub struct ModalInteraction {
/// Id of the interaction.
Expand Down Expand Up @@ -180,35 +179,22 @@ impl ModalInteraction {
}
}

// Manual impl needed to insert guild_id into resolved Role's
impl<'de> Deserialize<'de> for ModalInteraction {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;

let guild_id = remove_from_map_opt::<GuildId, _>(&mut map, "guild_id")?;
if let Some(guild_id) = guild_id {
add_guild_id_to_resolved(&mut map, guild_id);
let mut interaction = Self::deserialize(deserializer)?; // calls #[serde(remote)]-generated inherent method
if let (Some(guild_id), Some(member)) = (interaction.guild_id, &mut interaction.member) {
member.guild_id = guild_id;
// If `member` is present, `user` wasn't sent and is still filled with default data
interaction.user = member.user.clone();
}
Ok(interaction)
}
}

let member = remove_from_map_opt::<Member, _>(&mut map, "member")?;
let user = remove_from_map_opt(&mut map, "user")?
.or_else(|| member.as_ref().map(|m| m.user.clone()))
.ok_or_else(|| DeError::custom("expected user or member"))?;

Ok(Self {
member,
user,
id: remove_from_map(&mut map, "id")?,
guild_id,
application_id: remove_from_map(&mut map, "application_id")?,
data: remove_from_map(&mut map, "data")?,
channel_id: remove_from_map(&mut map, "channel_id")?,
token: remove_from_map(&mut map, "token")?,
version: remove_from_map(&mut map, "version")?,
message: remove_from_map_opt(&mut map, "message")?,
app_permissions: remove_from_map_opt(&mut map, "app_permissions")?,
locale: remove_from_map(&mut map, "locale")?,
guild_locale: remove_from_map_opt(&mut map, "guild_locale")?,
})
impl Serialize for ModalInteraction {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
Self::serialize(self, serializer) // calls #[serde(remote)]-generated inherent method
}
}

Expand Down
1 change: 1 addition & 0 deletions src/model/channel/guild_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct GuildChannel {
///
/// The original voice channel has an Id equal to the guild's Id,
/// incremented by one.
#[serde(default)]
pub guild_id: GuildId,
/// The type of the channel.
#[serde(rename = "type")]
Expand Down
1 change: 1 addition & 0 deletions src/model/channel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ impl Channel {
}
}

// Manual impl needed to emulate integer enum tags
impl<'de> Deserialize<'de> for Channel {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let map = JsonMap::deserialize(deserializer)?;
Expand Down
Loading