Skip to content

Commit fce19bb

Browse files
authored
Replace JsonMap with RawValue (#3313)
Entirely removes `JsonMap`, replacing all remaining uses with a combination of `RawValue` and helper structs for field access.
1 parent e552918 commit fce19bb

File tree

7 files changed

+90
-75
lines changed

7 files changed

+90
-75
lines changed

src/http/client.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,13 +1833,11 @@ impl Http {
18331833
pub async fn edit_member_me(
18341834
&self,
18351835
guild_id: GuildId,
1836-
map: &JsonMap,
1836+
map: &impl serde::Serialize,
18371837
audit_log_reason: Option<&str>,
18381838
) -> Result<Member> {
1839-
let body = to_vec(map)?;
1840-
18411839
self.fire(Request {
1842-
body: Some(body),
1840+
body: Some(to_vec(map)?),
18431841
multipart: None,
18441842
headers: audit_log_reason.map(reason_into_header),
18451843
method: LightMethod::Patch,

src/internal/prelude.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,3 @@ pub use super::utils::join_to_string;
1414
pub use crate::error::Error;
1515
pub use crate::error::Result;
1616
pub use crate::secrets::{SecretString, Token};
17-
18-
pub type JsonMap = serde_json::Map<String, Value>;

src/model/application/component.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use serde::de::Error as DeError;
22
use serde::ser::{Serialize, Serializer};
3-
use serde_json::from_value;
3+
use serde_json::value::RawValue;
44

55
use crate::model::prelude::*;
6-
use crate::model::utils::{default_true, deserialize_val};
6+
use crate::model::utils::default_true;
77

88
enum_number! {
99
/// The type of a component
@@ -52,19 +52,29 @@ pub enum ActionRowComponent {
5252

5353
impl<'de> Deserialize<'de> for ActionRowComponent {
5454
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
55-
let map = JsonMap::deserialize(deserializer)?;
55+
#[derive(Deserialize)]
56+
struct ActionRowRaw {
57+
#[serde(rename = "type")]
58+
kind: ComponentType,
59+
}
5660

57-
let raw_kind = map.get("type").ok_or_else(|| DeError::missing_field("type"))?.clone();
58-
let value = Value::from(map);
61+
let raw_data = <&RawValue>::deserialize(deserializer)?;
62+
let raw = ActionRowRaw::deserialize(raw_data).map_err(DeError::custom)?;
5963

60-
match deserialize_val(raw_kind)? {
61-
ComponentType::Button => from_value(value).map(ActionRowComponent::Button),
62-
ComponentType::InputText => from_value(value).map(ActionRowComponent::InputText),
64+
match raw.kind {
65+
ComponentType::Button => {
66+
Deserialize::deserialize(raw_data).map(ActionRowComponent::Button)
67+
},
68+
ComponentType::InputText => {
69+
Deserialize::deserialize(raw_data).map(ActionRowComponent::InputText)
70+
},
6371
ComponentType::StringSelect
6472
| ComponentType::UserSelect
6573
| ComponentType::RoleSelect
6674
| ComponentType::MentionableSelect
67-
| ComponentType::ChannelSelect => from_value(value).map(ActionRowComponent::SelectMenu),
75+
| ComponentType::ChannelSelect => {
76+
Deserialize::deserialize(raw_data).map(ActionRowComponent::SelectMenu)
77+
},
6878
ComponentType::ActionRow => {
6979
return Err(DeError::custom("Invalid component type ActionRow"));
7080
},

src/model/application/interaction.rs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use serde::de::{Deserialize, Deserializer, Error as DeError};
22
use serde::ser::{Serialize, Serializer};
3-
use serde_json::from_value;
3+
use serde_json::value::RawValue;
44

55
use super::{
66
CommandInteraction,
@@ -16,7 +16,7 @@ use crate::model::guild::PartialMember;
1616
use crate::model::id::{ApplicationId, GuildId, InteractionId, MessageId, UserId};
1717
use crate::model::monetization::Entitlement;
1818
use crate::model::user::User;
19-
use crate::model::utils::{StrOrInt, deserialize_val, remove_from_map};
19+
use crate::model::utils::StrOrInt;
2020

2121
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object)
2222
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
@@ -244,17 +244,27 @@ impl Interaction {
244244
// Manual impl needed to emulate integer enum tags
245245
impl<'de> Deserialize<'de> for Interaction {
246246
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> std::result::Result<Self, D::Error> {
247-
let map = JsonMap::deserialize(deserializer)?;
247+
#[derive(Deserialize)]
248+
struct InteractionRaw {
249+
#[serde(rename = "type")]
250+
kind: InteractionType,
251+
}
248252

249-
let raw_kind = map.get("type").ok_or_else(|| DeError::missing_field("type"))?.clone();
250-
let value = Value::from(map);
253+
let raw_data = <&RawValue>::deserialize(deserializer)?;
254+
let raw = InteractionRaw::deserialize(raw_data).map_err(DeError::custom)?;
251255

252-
match deserialize_val(raw_kind)? {
253-
InteractionType::Command => from_value(value).map(Interaction::Command),
254-
InteractionType::Component => from_value(value).map(Interaction::Component),
255-
InteractionType::Autocomplete => from_value(value).map(Interaction::Autocomplete),
256-
InteractionType::Modal => from_value(value).map(Interaction::Modal),
257-
InteractionType::Ping => from_value(value).map(Interaction::Ping),
256+
match raw.kind {
257+
InteractionType::Command => {
258+
Deserialize::deserialize(raw_data).map(Interaction::Command)
259+
},
260+
InteractionType::Component => {
261+
Deserialize::deserialize(raw_data).map(Interaction::Component)
262+
},
263+
InteractionType::Autocomplete => {
264+
Deserialize::deserialize(raw_data).map(Interaction::Autocomplete)
265+
},
266+
InteractionType::Modal => Deserialize::deserialize(raw_data).map(Interaction::Modal),
267+
InteractionType::Ping => Deserialize::deserialize(raw_data).map(Interaction::Ping),
258268
InteractionType(_) => return Err(DeError::custom("Unknown interaction type")),
259269
}
260270
.map_err(DeError::custom)
@@ -494,16 +504,23 @@ pub enum MessageInteractionMetadata {
494504

495505
impl<'de> serde::Deserialize<'de> for MessageInteractionMetadata {
496506
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
497-
let mut data = JsonMap::deserialize(deserializer)?;
498-
let kind: InteractionType = remove_from_map(&mut data, "type")?;
507+
#[derive(Deserialize)]
508+
struct InteractionRaw {
509+
#[serde(rename = "type")]
510+
kind: InteractionType,
511+
}
499512

500-
match kind {
501-
InteractionType::Command => deserialize_val(Value::from(data)).map(Self::Command),
502-
InteractionType::Component => deserialize_val(Value::from(data)).map(Self::Component),
503-
InteractionType::Modal => deserialize_val(Value::from(data)).map(Self::ModalSubmit),
513+
let raw_data = <&RawValue>::deserialize(deserializer)?;
514+
let raw = InteractionRaw::deserialize(raw_data).map_err(DeError::custom)?;
515+
516+
match raw.kind {
517+
InteractionType::Command => Deserialize::deserialize(raw_data).map(Self::Command),
518+
InteractionType::Component => Deserialize::deserialize(raw_data).map(Self::Component),
519+
InteractionType::Modal => Deserialize::deserialize(raw_data).map(Self::ModalSubmit),
504520

505521
unknown => Ok(Self::Unknown(unknown)),
506522
}
523+
.map_err(DeError::custom)
507524
}
508525
}
509526

src/model/channel/mod.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ mod reaction;
1111

1212
use std::fmt;
1313

14-
use serde::de::{Error as DeError, Unexpected};
14+
use serde::de::Error as DeError;
1515
use serde::ser::SerializeMap as _;
16-
use serde_json::from_value;
16+
use serde_json::value::RawValue;
1717

1818
pub use self::attachment::*;
1919
#[cfg(feature = "model")]
@@ -156,22 +156,20 @@ impl Channel {
156156
// Manual impl needed to emulate integer enum tags
157157
impl<'de> Deserialize<'de> for Channel {
158158
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
159-
let map = JsonMap::deserialize(deserializer)?;
160-
161-
let kind = {
162-
let kind = map.get("type").ok_or_else(|| DeError::missing_field("type"))?;
163-
kind.as_u64().ok_or_else(|| {
164-
DeError::invalid_type(
165-
Unexpected::Other("non-positive integer"),
166-
&"a positive integer",
167-
)
168-
})?
169-
};
159+
#[derive(Deserialize)]
160+
struct ChannelRaw {
161+
#[serde(rename = "type")]
162+
kind: u64,
163+
}
170164

171-
let value = Value::from(map);
172-
match kind {
173-
0 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 => from_value(value).map(Channel::Guild),
174-
1 => from_value(value).map(Channel::Private),
165+
let raw_data = <&RawValue>::deserialize(deserializer)?;
166+
let raw = ChannelRaw::deserialize(raw_data).map_err(DeError::custom)?;
167+
168+
match raw.kind {
169+
0 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 => {
170+
Deserialize::deserialize(raw_data).map(Channel::Guild)
171+
},
172+
1 => Deserialize::deserialize(raw_data).map(Channel::Private),
175173
_ => return Err(DeError::custom("Unknown channel type")),
176174
}
177175
.map_err(DeError::custom)

src/model/event.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,11 @@ pub struct MessageDeleteEvent {
468468
/// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#message-update).
469469
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
470470
#[derive(Clone, Debug, Deserialize, Serialize)]
471+
// This ensures that `RawValue` is further supported in nested fields of `Message`.
472+
// Fields underneath #[serde(flatten)] cannot be deserialized as `RawValue`.
473+
#[serde(transparent)]
471474
#[non_exhaustive]
472475
pub struct MessageUpdateEvent {
473-
#[serde(flatten)]
474476
pub message: Message,
475477
}
476478

@@ -971,7 +973,7 @@ fn raw_value_len(val: &RawValue) -> usize {
971973
// Manual impl needed to emulate integer enum tags
972974
impl<'de> Deserialize<'de> for GatewayEvent {
973975
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
974-
#[derive(Debug, Clone, Deserialize)]
976+
#[derive(Deserialize)]
975977
struct GatewayEventRaw<'a> {
976978
op: Opcode,
977979
#[serde(rename = "s")]

src/model/utils.rs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fmt;
33
use arrayvec::ArrayVec;
44
use serde::de::Error as DeError;
55
use serde_cow::CowStr;
6+
use serde_json::value::RawValue;
67
use small_fixed_array::FixedString;
78

89
use super::prelude::*;
@@ -43,22 +44,6 @@ pub(super) fn icon_url(id: GuildId, icon: Option<&ImageHash>) -> Option<String>
4344
})
4445
}
4546

46-
pub fn deserialize_val<T, E>(val: Value) -> StdResult<T, E>
47-
where
48-
T: serde::de::DeserializeOwned,
49-
E: serde::de::Error,
50-
{
51-
T::deserialize(val).map_err(serde::de::Error::custom)
52-
}
53-
54-
pub fn remove_from_map<T, E>(map: &mut JsonMap, key: &'static str) -> StdResult<T, E>
55-
where
56-
T: serde::de::DeserializeOwned,
57-
E: serde::de::Error,
58-
{
59-
map.remove(key).ok_or_else(|| serde::de::Error::missing_field(key)).and_then(deserialize_val)
60-
}
61-
6247
pub(super) enum StrOrInt<'de> {
6348
String(String),
6449
Str(&'de str),
@@ -261,6 +246,12 @@ pub fn deserialize_components<'de, D>(deserializer: D) -> Result<FixedArray<Acti
261246
where
262247
D: Deserializer<'de>,
263248
{
249+
#[derive(Deserialize)]
250+
struct MinComponent {
251+
#[serde(rename = "type")]
252+
kind: u8,
253+
}
254+
264255
struct ComponentsVisitor;
265256

266257
impl<'de> Visitor<'de> for ComponentsVisitor {
@@ -276,22 +267,23 @@ where
276267
{
277268
let mut components = Vec::with_capacity(seq.size_hint().unwrap_or_default());
278269

279-
while let Some(map) = seq.next_element::<JsonMap>()? {
270+
while let Some(raw) = seq.next_element::<&RawValue>()? {
280271
// We deserialize only the `kind` field to determine the component type.
281272
// We later use this to check if its a supported component before deserializing the
282273
// entire payload.
283-
let raw_kind =
284-
map.get("type").ok_or_else(|| DeError::missing_field("type"))?.clone();
285-
let kind: i64 = deserialize_val(raw_kind)?;
274+
let min_component =
275+
MinComponent::deserialize(raw).map_err(serde::de::Error::custom)?;
286276

287277
// Action rows are the only top level component supported in serenity at this time.
288-
if kind == 1 {
289-
let value = Value::from(map);
290-
components.push(ActionRow::deserialize(value).map_err(DeError::custom)?);
278+
if min_component.kind == 1 {
279+
components.push(ActionRow::deserialize(raw).map_err(serde::de::Error::custom)?);
291280
} else {
292281
// Top level component is not an action row and cannot be supported on
293282
// serenity@current without breaking changes, so we skip them.
294-
tracing::debug!("Skipping component with unsupported kind: {kind}");
283+
tracing::debug!(
284+
"Skipping component with unsupported kind: {}",
285+
min_component.kind
286+
);
295287
}
296288
}
297289

0 commit comments

Comments
 (0)