aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/model/channel/reaction.rs89
-rw-r--r--tests/resources/message_reaction_add_2.json1
-rw-r--r--tests/resources/message_reaction_remove_2.json1
-rw-r--r--tests/test_deser.rs2
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]