From 1e1079a90448a8dfdd8c272efb3e92faec9f601c Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 30 Jul 2016 11:50:58 -0700 Subject: [PATCH] Extract enum serialization into a macro. --- src/call/mod.rs | 71 ++---------------------------- src/lib.rs | 3 ++ src/macros.rs | 60 +++++++++++++++++++++++++ src/presence.rs | 73 +++---------------------------- src/room/guest_access.rs | 71 +++--------------------------- src/room/history_visibility.rs | 77 +++----------------------------- src/room/join_rules.rs | 77 +++----------------------------- src/room/member.rs | 80 ++++------------------------------ 8 files changed, 100 insertions(+), 412 deletions(-) create mode 100644 src/macros.rs diff --git a/src/call/mod.rs b/src/call/mod.rs index fdff4174..b64e5c13 100644 --- a/src/call/mod.rs +++ b/src/call/mod.rs @@ -2,13 +2,6 @@ //! //! This module also contains types shared by events in its child namespaces. -use std::fmt::{Display, Formatter, Error as FmtError}; -use std::str::FromStr; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use {ParseError, Visitor}; - pub mod answer; pub mod candidates; pub mod hangup; @@ -32,65 +25,9 @@ pub enum SessionDescriptionType { Offer, } -impl Display for SessionDescriptionType { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - let session_description_type_str = match *self { - SessionDescriptionType::Answer => "answer", - SessionDescriptionType::Offer => "offer", - }; - - write!(f, "{}", session_description_type_str) - } -} - -impl FromStr for SessionDescriptionType { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - match s { - "answer" => Ok(SessionDescriptionType::Answer), - "offer" => Ok(SessionDescriptionType::Offer), - _ => Err(ParseError), - } - } -} - -impl Serialize for SessionDescriptionType { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deserialize for SessionDescriptionType { - fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.deserialize_str(Visitor::new()) - } -} - -#[cfg(test)] -mod tests { - use serde_json::{from_str, to_string}; - - use super::SessionDescriptionType; - - #[test] - fn session_description_types_serialize_to_display_form() { - assert_eq!( - to_string(&SessionDescriptionType::Answer).unwrap(), - r#""answer""# - ); - } - - #[test] - fn session_description_types_deserialize_from_display_form() { - assert_eq!( - from_str::(r#""answer""#).unwrap(), - SessionDescriptionType::Answer - ); - } - - #[test] - fn invalid_session_description_types_fail_deserialization() { - assert!(from_str::(r#""bad""#).is_err()); +impl_enum! { + SessionDescriptionType { + Answer => "answer", + Offer => "offer", } } diff --git a/src/lib.rs b/src/lib.rs index c9f6e1a2..50a11e64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,9 @@ use serde::{Deserialize, Deserializer, Error as SerdeError, Serialize, Serialize use serde::de::Visitor as SerdeVisitor; use serde_json::Value; +#[macro_use] +mod macros; + pub mod call; pub mod presence; pub mod receipt; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 00000000..cb9bd880 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,60 @@ +macro_rules! impl_enum { + ($name:ident { $($variant:ident => $s:expr,)+ }) => { + impl ::std::fmt::Display for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + let variant = match *self { + $($name::$variant => $s,)* + }; + + write!(f, "{}", variant) + } + } + + impl ::std::str::FromStr for $name { + type Err = $crate::ParseError; + + fn from_str(s: &str) -> Result { + match s { + $($s => Ok($name::$variant),)* + _ => Err($crate::ParseError), + } + } + } + + impl ::serde::Serialize for $name { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ::serde::Serializer { + serializer.serialize_str(&self.to_string()) + } + } + + impl ::serde::Deserialize for $name { + fn deserialize(deserializer: &mut D) -> Result + where D: ::serde::Deserializer { + deserializer.deserialize_str($crate::Visitor::new()) + } + } + + #[cfg(test)] + mod serialization_tests { + use serde_json::{from_str, to_string}; + + use super::$name; + + #[test] + fn serialization_to_display_form() { + $(assert_eq!(to_string(&$name::$variant).unwrap(), stringify!($s));)* + } + + #[test] + fn deserialization_from_display_form() { + $(assert_eq!(from_str::<$name>(stringify!($s)).unwrap(), $name::$variant);)* + } + + #[test] + fn deserialization_fails_for_invalid_string_value() { + assert!(from_str::<$name>(r#""invalid variant name""#).is_err()); + } + } + } +} diff --git a/src/presence.rs b/src/presence.rs index 3799e7cb..69f40df3 100644 --- a/src/presence.rs +++ b/src/presence.rs @@ -1,12 +1,8 @@ //! Types for the *m.presence* event. -use std::fmt::{Display, Formatter, Error as FmtError}; -use std::str::FromStr; - use ruma_identifiers::{EventId, UserId}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use {Event, ParseError, Visitor}; +use Event; /// Informs the client of a user's presence state change. pub type PresenceEvent = Event; @@ -53,67 +49,10 @@ pub struct PresenceEventExtraContent { pub event_id: EventId, } -impl Display for PresenceState { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - let presence_state_str = match *self { - PresenceState::Offline => "offline", - PresenceState::Online => "online", - PresenceState::Unavailable => "unavailable", - }; - - write!(f, "{}", presence_state_str) - } -} - -impl FromStr for PresenceState { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - match s { - "offline" => Ok(PresenceState::Offline), - "online" => Ok(PresenceState::Online), - "unavailable" => Ok(PresenceState::Unavailable), - _ => Err(ParseError), - } - } -} - -impl Serialize for PresenceState { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deserialize for PresenceState { - fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.deserialize_str(Visitor::new()) - } -} - -#[cfg(test)] -mod tests { - use serde_json::{from_str, to_string}; - - use super::PresenceState; - - #[test] - fn presence_states_serialize_to_display_form() { - assert_eq!( - to_string(&PresenceState::Offline).unwrap(), - r#""offline""# - ); - } - - #[test] - fn presence_states_deserialize_from_display_form() { - assert_eq!( - from_str::(r#""offline""#).unwrap(), - PresenceState::Offline - ); - } - - #[test] - fn invalid_presence_states_fail_deserialization() { - assert!(from_str::(r#""bad""#).is_err()); +impl_enum! { + PresenceState { + Offline => "offline", + Online => "online", + Unavailable => "unavailable", } } diff --git a/src/room/guest_access.rs b/src/room/guest_access.rs index 78b67fc9..61dee7a5 100644 --- a/src/room/guest_access.rs +++ b/src/room/guest_access.rs @@ -1,11 +1,6 @@ //! Types for the *m.room.guest_access* event. -use std::fmt::{Display, Formatter, Error as FmtError}; -use std::str::FromStr; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use {StateEvent, ParseError, Visitor}; +use StateEvent; /// Controls whether guest users are allowed to join rooms. /// @@ -30,65 +25,9 @@ pub enum GuestAccess { Forbidden, } -impl Display for GuestAccess { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - let guest_access_str = match *self { - GuestAccess::CanJoin => "can_join", - GuestAccess::Forbidden => "forbidden", - }; - - write!(f, "{}", guest_access_str) - } -} - -impl FromStr for GuestAccess { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - match s { - "can_join" => Ok(GuestAccess::CanJoin), - "forbidden" => Ok(GuestAccess::Forbidden), - _ => Err(ParseError), - } - } -} - -impl Serialize for GuestAccess { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deserialize for GuestAccess { - fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.deserialize_str(Visitor::new()) - } -} - -#[cfg(test)] -mod tests { - use serde_json::{from_str, to_string}; - - use super::GuestAccess; - - #[test] - fn guest_access_serializes_to_display_form() { - assert_eq!( - to_string(&GuestAccess::CanJoin).unwrap(), - r#""can_join""# - ); - } - - #[test] - fn guest_access_deserializes_from_display_form() { - assert_eq!( - from_str::(r#""can_join""#).unwrap(), - GuestAccess::CanJoin - ); - } - - #[test] - fn invalid_guest_access_fails_deserialization() { - assert!(from_str::(r#""bad""#).is_err()); +impl_enum! { + GuestAccess { + CanJoin => "can_join", + Forbidden => "forbidden", } } diff --git a/src/room/history_visibility.rs b/src/room/history_visibility.rs index acb1e4f6..4fa30cf1 100644 --- a/src/room/history_visibility.rs +++ b/src/room/history_visibility.rs @@ -1,11 +1,6 @@ //! Types for the *m.room.history_visibility* event. -use std::fmt::{Display, Formatter, Error as FmtError}; -use std::str::FromStr; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use {StateEvent, ParseError, Visitor}; +use StateEvent; /// This event controls whether a member of a room can see the events that happened in a room from /// before they joined. @@ -40,69 +35,11 @@ pub enum HistoryVisibility { WorldReadable, } -impl Display for HistoryVisibility { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - let history_visibility_str = match *self { - HistoryVisibility::Invited => "invited", - HistoryVisibility::Joined => "joined", - HistoryVisibility::Shared => "shared", - HistoryVisibility::WorldReadable => "world_readable", - }; - - write!(f, "{}", history_visibility_str) - } -} - -impl FromStr for HistoryVisibility { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - match s { - "invited" => Ok(HistoryVisibility::Invited), - "joined" => Ok(HistoryVisibility::Joined), - "shared" => Ok(HistoryVisibility::Shared), - "world_readable" => Ok(HistoryVisibility::WorldReadable), - _ => Err(ParseError), - } - } -} - -impl Serialize for HistoryVisibility { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deserialize for HistoryVisibility { - fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.deserialize_str(Visitor::new()) - } -} - -#[cfg(test)] -mod tests { - use serde_json::{from_str, to_string}; - - use super::HistoryVisibility; - - #[test] - fn history_visibility_serializes_to_display_form() { - assert_eq!( - to_string(&HistoryVisibility::Invited).unwrap(), - r#""invited""# - ); - } - - #[test] - fn history_visibility_deserializes_from_display_form() { - assert_eq!( - from_str::(r#""invited""#).unwrap(), - HistoryVisibility::Invited - ); - } - - #[test] - fn invalid_history_visibility_fails_deserialization() { - assert!(from_str::(r#""bad""#).is_err()); +impl_enum! { + HistoryVisibility { + Invited => "invited", + Joined => "joined", + Shared => "shared", + WorldReadable => "world_readable", } } diff --git a/src/room/join_rules.rs b/src/room/join_rules.rs index d5e4f05b..7af06767 100644 --- a/src/room/join_rules.rs +++ b/src/room/join_rules.rs @@ -1,11 +1,6 @@ //! Types for the *m.room.join_rules* event. -use std::fmt::{Display, Formatter, Error as FmtError}; -use std::str::FromStr; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use {StateEvent, ParseError, Visitor}; +use StateEvent; /// Describes how users are allowed to join the room. pub type JoinRulesEvent = StateEvent; @@ -34,69 +29,11 @@ pub enum JoinRule { Public, } -impl Display for JoinRule { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - let join_rule_str = match *self { - JoinRule::Invite => "invite", - JoinRule::Knock => "knock", - JoinRule::Private => "private", - JoinRule::Public => "public", - }; - - write!(f, "{}", join_rule_str) - } -} - -impl FromStr for JoinRule { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - match s { - "invite" => Ok(JoinRule::Invite), - "knock" => Ok(JoinRule::Knock), - "private" => Ok(JoinRule::Private), - "public" => Ok(JoinRule::Public), - _ => Err(ParseError), - } - } -} - -impl Serialize for JoinRule { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deserialize for JoinRule { - fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.deserialize_str(Visitor::new()) - } -} - -#[cfg(test)] -mod tests { - use serde_json::{from_str, to_string}; - - use super::JoinRule; - - #[test] - fn join_rules_serialize_to_display_form() { - assert_eq!( - to_string(&JoinRule::Invite).unwrap(), - r#""invite""# - ); - } - - #[test] - fn join_rules_deserialize_from_display_form() { - assert_eq!( - from_str::(r#""invite""#).unwrap(), - JoinRule::Invite - ); - } - - #[test] - fn invalid_join_rules_fail_deserialization() { - assert!(from_str::(r#""bad""#).is_err()); +impl_enum! { + JoinRule { + Invite => "invite", + Knock => "knock", + Private => "private", + Public => "public", } } diff --git a/src/room/member.rs b/src/room/member.rs index b3b67dd3..b504e419 100644 --- a/src/room/member.rs +++ b/src/room/member.rs @@ -1,11 +1,6 @@ //! Types for the *m.room.member* event. -use std::fmt::{Display, Formatter, Error as FmtError}; -use std::str::FromStr; - -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -use {StateEvent, ParseError, Visitor}; +use StateEvent; use stripped::StrippedState; /// The current membership state of a user in the room. @@ -65,71 +60,12 @@ pub struct MemberEventExtraContent { pub invite_room_state: Option>, } -impl Display for MembershipState { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - let membership_state_str = match *self { - MembershipState::Ban => "ban", - MembershipState::Invite => "invite", - MembershipState::Join => "join", - MembershipState::Knock => "knock", - MembershipState::Leave => "leave", - }; - - write!(f, "{}", membership_state_str) - } -} - -impl FromStr for MembershipState { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - match s { - "ban" => Ok(MembershipState::Ban), - "invite" => Ok(MembershipState::Invite), - "join" => Ok(MembershipState::Join), - "knock" => Ok(MembershipState::Knock), - "leave" => Ok(MembershipState::Leave), - _ => Err(ParseError), - } - } -} - -impl Serialize for MembershipState { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { - serializer.serialize_str(&self.to_string()) - } -} - -impl Deserialize for MembershipState { - fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { - deserializer.deserialize_str(Visitor::new()) - } -} - -#[cfg(test)] -mod tests { - use serde_json::{from_str, to_string}; - - use super::MembershipState; - - #[test] - fn membership_states_serialize_to_display_form() { - assert_eq!( - to_string(&MembershipState::Ban).unwrap(), - r#""ban""# - ); - } - - #[test] - fn membership_states_deserialize_from_display_form() { - assert_eq!( - from_str::(r#""ban""#).unwrap(), - MembershipState::Ban - ); - } - - #[test] - fn invalid_membership_states_fail_deserialization() { - assert!(from_str::(r#""bad""#).is_err()); +impl_enum! { + MembershipState { + Ban => "ban", + Invite => "invite", + Join => "join", + Knock => "knock", + Leave => "leave", } }