Use Serde annotations instead of manual implementation for enums.

This commit is contained in:
Jimmy Cuadra 2016-08-03 23:43:08 -07:00
parent 85578cf76f
commit 2eb07f5abd
9 changed files with 38 additions and 164 deletions

View File

@ -17,17 +17,12 @@ pub struct SessionDescription {
}
/// The type of VoIP session description.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum SessionDescriptionType {
/// An answer.
#[serde(rename="answer")]
Answer,
/// An offer.
#[serde(rename="offer")]
Offer,
}
impl_enum! {
SessionDescriptionType {
Answer => "answer",
Offer => "offer",
}
}

View File

@ -10,17 +10,12 @@ extern crate serde;
extern crate serde_json;
use std::fmt::{Display, Formatter, Error as FmtError};
use std::marker::PhantomData;
use std::str::FromStr;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Deserializer, Error as SerdeError, Serialize, Serializer};
use serde::de::Visitor as SerdeVisitor;
use serde::de::Visitor;
use serde_json::Value;
#[macro_use]
mod macros;
pub mod call;
pub mod presence;
pub mod receipt;
@ -160,14 +155,6 @@ pub struct StateEvent<C, E> where C: Deserialize + Serialize, E: Deserialize + S
pub user_id: UserId,
}
/// An error when attempting to convert a string to an enum that only accepts certain values.
pub struct ParseError;
/// A Serde `Visitor` for deserializing various ruma-events enums.
struct Visitor<T> where T: Deserialize + FromStr {
_phantom: PhantomData<T>,
}
impl Display for EventType {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let event_type_str = match *self {
@ -240,7 +227,7 @@ impl Deserialize for EventType {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error> where D: Deserializer {
struct EventTypeVisitor;
impl SerdeVisitor for EventTypeVisitor {
impl Visitor for EventTypeVisitor {
type Value = EventType;
fn visit_str<E>(&mut self, v: &str) -> Result<Self::Value, E> where E: SerdeError {
@ -252,24 +239,6 @@ impl Deserialize for EventType {
}
}
impl<T> Visitor<T> where T: Deserialize + FromStr {
pub fn new() -> Visitor<T> {
Visitor {
_phantom: PhantomData,
}
}
}
impl<T> SerdeVisitor for Visitor<T> where T: Deserialize + FromStr {
type Value = T;
fn visit_str<E>(&mut self, v: &str) -> Result<Self::Value, E> where E: SerdeError {
v.parse().map_err(|_| {
E::invalid_value(v)
})
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_str, to_string};

View File

@ -1,60 +0,0 @@
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<Self, Self::Err> {
match s {
$($s => Ok($name::$variant),)*
_ => Err($crate::ParseError),
}
}
}
impl ::serde::Serialize for $name {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: ::serde::Serializer {
serializer.serialize_str(&self.to_string())
}
}
impl ::serde::Deserialize for $name {
fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
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());
}
}
}
}

View File

@ -33,15 +33,18 @@ pub struct PresenceEventContent {
}
/// A description of a user's connectivity and availability for chat.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum PresenceState {
/// Disconnected from the service.
#[serde(rename="offline")]
Offline,
/// Connected to the service.
#[serde(rename="online")]
Online,
/// Connected to the service but not available for chat.
#[serde(rename="unavailable")]
Unavailable,
}
@ -51,11 +54,3 @@ pub struct PresenceEventExtraContent {
/// The unique identifier for the event.
pub event_id: EventId,
}
impl_enum! {
PresenceState {
Offline => "offline",
Online => "online",
Unavailable => "unavailable",
}
}

View File

@ -16,18 +16,13 @@ pub struct GuestAccessEventContent {
}
/// A policy for guest user access to a room.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum GuestAccess {
/// Guests are allowed to join the room.
#[serde(rename="can_join")]
CanJoin,
/// Guests are not allowed to join the room.
#[serde(rename="forbidden")]
Forbidden,
}
impl_enum! {
GuestAccess {
CanJoin => "can_join",
Forbidden => "forbidden",
}
}

View File

@ -14,32 +14,27 @@ pub struct HistoryVisibilityEventContent {
}
/// Who can see a room's history.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum HistoryVisibility {
/// Previous events are accessible to newly joined members from the point they were invited
/// onwards. Events stop being accessible when the member's state changes to something other
/// than *invite* or *join*.
#[serde(rename="invited")]
Invited,
/// Previous events are accessible to newly joined members from the point they joined the room
/// onwards. Events stop being accessible when the member's state changes to something other
/// than *join*.
#[serde(rename="joined")]
Joined,
/// Previous events are always accessible to newly joined members. All events in the room are
/// accessible, even those sent when the member was not a part of the room.
#[serde(rename="shared")]
Shared,
/// All events while this is the `HistoryVisibility` value may be shared by any
/// participating homeserver with anyone, regardless of whether they have ever joined the room.
#[serde(rename="world_readable")]
WorldReadable,
}
impl_enum! {
HistoryVisibility {
Invited => "invited",
Joined => "joined",
Shared => "shared",
WorldReadable => "world_readable",
}
}

View File

@ -13,27 +13,22 @@ pub struct JoinRulesEventContent {
}
/// The rule used for users wishing to join this room.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum JoinRule {
/// A user who wishes to join the room must first receive an invite to the room from someone
/// already inside of the room.
#[serde(rename="invite")]
Invite,
/// Reserved but not yet implemented by the Matrix specification.
#[serde(rename="knock")]
Knock,
/// Reserved but not yet implemented by the Matrix specification.
#[serde(rename="private")]
Private,
/// Anyone can join the room without any prior action.
#[serde(rename="public")]
Public,
}
impl_enum! {
JoinRule {
Invite => "invite",
Knock => "knock",
Private => "private",
Public => "public",
}
}

View File

@ -37,21 +37,26 @@ pub struct MemberEventContent {
}
/// The membership state of a user.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum MembershipState {
/// The user is banned.
#[serde(rename="ban")]
Ban,
/// The user has been invited.
#[serde(rename="invite")]
Invite,
/// The user has joined.
#[serde(rename="join")]
Join,
/// The user has requested to join.
#[serde(rename="knock")]
Knock,
/// The user has left.
#[serde(rename="leave")]
Leave,
}
@ -62,13 +67,3 @@ pub struct MemberEventExtraContent {
#[serde(skip_serializing_if="Option::is_none")]
pub invite_room_state: Option<Vec<StrippedState>>,
}
impl_enum! {
MembershipState {
Ban => "ban",
Invite => "invite",
Join => "join",
Knock => "knock",
Leave => "leave",
}
}

View File

@ -10,30 +10,38 @@ use super::ImageInfo;
pub type MessageEvent = RoomEvent<MessageEventContent, ()>;
/// The message type of message event, e.g. `m.image` or `m.text`.
#[derive(Debug, PartialEq)]
#[derive(Debug, Deserialize, PartialEq, Serialize)]
pub enum MessageType {
/// An audio message.
#[serde(rename="m.audio")]
Audio,
/// An emote message.
#[serde(rename="m.emote")]
Emote,
/// A file message.
#[serde(rename="m.file")]
File,
/// An image message.
#[serde(rename="m.image")]
Image,
/// A location message.
#[serde(rename="m.location")]
Location,
/// A notice message.
#[serde(rename="m.notice")]
Notice,
/// A text message.
#[serde(rename="m.text")]
Text,
/// A video message.
#[serde(rename="m.video")]
Video,
}
@ -230,19 +238,6 @@ pub struct VideoInfo {
pub w: Option<u64>,
}
impl_enum! {
MessageType {
Audio => "m.audio",
Emote => "m.emote",
File => "m.file",
Image => "m.image",
Location => "m.location",
Notice => "m.notice",
Text => "m.text",
Video => "m.video",
}
}
impl Serialize for MessageEventContent {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
match *self {
@ -342,7 +337,7 @@ impl Deserialize for MessageEventContent {
}
#[cfg(test)]
mod message_event_content_serialization_tests {
mod tests {
use serde_json::{from_str, to_string};
use super::{AudioMessageEventContent, MessageType, MessageEventContent};