diff options
| -rw-r--r-- | src/model/channel/reaction.rs | 89 | ||||
| -rw-r--r-- | tests/resources/message_reaction_add_2.json | 1 | ||||
| -rw-r--r-- | tests/resources/message_reaction_remove_2.json | 1 | ||||
| -rw-r--r-- | tests/test_deser.rs | 2 |
4 files changed, 90 insertions, 3 deletions
diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs index 32f6aa8..1e555ed 100644 --- a/src/model/channel/reaction.rs +++ b/src/model/channel/reaction.rs @@ -1,3 +1,4 @@ +use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor}; use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite}; use ::client::rest; use ::internal::prelude::*; @@ -96,8 +97,7 @@ impl Reaction { /// The type of a [`Reaction`] sent. /// /// [`Reaction`]: struct.Reaction.html -#[derive(Clone, Debug, Deserialize)] -#[serde(untagged)] +#[derive(Clone, Debug)] pub enum ReactionType { /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the /// guild. @@ -114,10 +114,93 @@ pub enum ReactionType { name: String, }, /// A reaction with a twemoji. - #[serde(rename="name")] Unicode(String), } +impl<'de> Deserialize<'de> for ReactionType { + fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> { + enum Field { + Id, + Name, + } + + impl<'de> Deserialize<'de> for Field { + fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> { + struct FieldVisitor; + + impl<'de> Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut Formatter) -> FmtResult { + formatter.write_str("`id` or `name`") + } + + fn visit_str<E: DeError>(self, value: &str) -> StdResult<Field, E> { + match value { + "id" => Ok(Field::Id), + "name" => Ok(Field::Name), + _ => Err(DeError::unknown_field(value, FIELDS)), + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct ReactionTypeVisitor; + + impl<'de> Visitor<'de> for ReactionTypeVisitor { + type Value = ReactionType; + + fn expecting(&self, formatter: &mut Formatter) -> FmtResult { + formatter.write_str("enum ReactionType") + } + + fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> { + let mut id = None; + let mut name = None; + + while let Some(key) = map.next_key()? { + match key { + Field::Id => { + if id.is_some() { + return Err(DeError::duplicate_field("id")); + } + + if let Ok(emoji_id) = map.next_value::<EmojiId>() { + id = Some(emoji_id) + } + }, + Field::Name => { + if name.is_some() { + return Err(DeError::duplicate_field("name")); + } + + name = Some(map.next_value()?); + }, + } + } + + let name = name.ok_or_else(|| DeError::missing_field("name"))?; + + Ok(if let Some(id) = id { + ReactionType::Custom { + id: id, + name: name, + } + } else { + ReactionType::Unicode(name) + }) + } + } + + const FIELDS: &'static [&'static str] = &["id", "name"]; + + deserializer.deserialize_map(ReactionTypeVisitor) + } +} + impl ReactionType { /// Creates a data-esque display of the type. This is not very useful for /// displaying, as the primary client can not render it, but can be useful diff --git a/tests/resources/message_reaction_add_2.json b/tests/resources/message_reaction_add_2.json new file mode 100644 index 0000000..ed3d807 --- /dev/null +++ b/tests/resources/message_reaction_add_2.json @@ -0,0 +1 @@ +{"user_id":"114941315417899012","message_id":"307288080891772929","emoji":{"name":"👍","id":null},"channel_id":"244567637332328449"} diff --git a/tests/resources/message_reaction_remove_2.json b/tests/resources/message_reaction_remove_2.json new file mode 100644 index 0000000..9c4f106 --- /dev/null +++ b/tests/resources/message_reaction_remove_2.json @@ -0,0 +1 @@ +{"user_id":"71924901186908160","message_id":"306912491836014592","emoji":{"name":"😋","id":null},"channel_id":"110805314659438592"} diff --git a/tests/test_deser.rs b/tests/test_deser.rs index a2d1be7..8216c57 100644 --- a/tests/test_deser.rs +++ b/tests/test_deser.rs @@ -122,11 +122,13 @@ fn message_update() { #[test] fn message_reaction_add() { p!(ReactionAddEvent, "message_reaction_add_1"); + p!(ReactionAddEvent, "message_reaction_add_2"); } #[test] fn message_reaction_remove() { p!(ReactionRemoveEvent, "message_reaction_remove_1"); + p!(ReactionRemoveEvent, "message_reaction_remove_2"); } #[test] |