From 32733cf7825944582f154fe94bd8a507f7206f19 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 10 Dec 2019 22:42:46 +0100 Subject: [PATCH] Further simplify deserialization --- src/event_id.rs | 20 +++----------------- src/lib.rs | 19 ++++++++++++++++++- src/room_alias_id.rs | 20 +++----------------- src/room_id.rs | 20 +++----------------- src/room_id_or_room_alias_id.rs | 26 ++++++++------------------ src/room_version_id.rs | 20 +++----------------- src/user_id.rs | 20 +++----------------- 7 files changed, 41 insertions(+), 104 deletions(-) diff --git a/src/event_id.rs b/src/event_id.rs index fc582526..f70cd50c 100644 --- a/src/event_id.rs +++ b/src/event_id.rs @@ -7,13 +7,10 @@ use std::{ #[cfg(feature = "diesel")] use diesel::sql_types::Text; -use serde::{ - de::{Error as SerdeError, Expected, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use url::Host; -use crate::{display, error::Error, generate_localpart, parse_id}; +use crate::{deserialize_id, display, error::Error, generate_localpart, parse_id}; /// A Matrix event ID. /// @@ -155,10 +152,7 @@ impl<'de> Deserialize<'de> for EventId { where D: Deserializer<'de>, { - String::deserialize(deserializer).and_then(|v| { - EventId::try_from(&v as &str) - .map_err(|_| SerdeError::invalid_value(Unexpected::Str(&v), &ExpectedEventId)) - }) + deserialize_id(deserializer, "a Matrix event ID as a string") } } @@ -189,14 +183,6 @@ impl<'a> TryFrom<&'a str> for EventId { } } -struct ExpectedEventId; - -impl Expected for ExpectedEventId { - fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult { - write!(formatter, "a Matrix event ID as a string") - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom; diff --git a/src/lib.rs b/src/lib.rs index baab2bc1..6a7d9277 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,9 +14,13 @@ #[cfg_attr(feature = "diesel", macro_use)] extern crate diesel; -use std::fmt::{Formatter, Result as FmtResult}; +use std::{ + convert::TryFrom, + fmt::{Formatter, Result as FmtResult}, +}; use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use serde::de::{self, Deserialize as _, Deserializer, Unexpected}; use url::Url; pub use url::Host; @@ -112,3 +116,16 @@ fn parse_id(required_sigil: char, id: &str) -> Result<(&str, Host, u16), Error> Ok((localpart, host, port)) } + +/// Deserializes any type of id using the provided TryFrom implementation. +/// +/// This is a helper function to reduce the boilerplate of the Deserialize implementations. +fn deserialize_id<'de, D, T>(deserializer: D, expected_str: &str) -> Result +where + D: Deserializer<'de>, + T: for<'a> TryFrom<&'a str>, +{ + String::deserialize(deserializer).and_then(|v| { + T::try_from(&v).map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &expected_str)) + }) +} diff --git a/src/room_alias_id.rs b/src/room_alias_id.rs index 5267e1e1..0883f293 100644 --- a/src/room_alias_id.rs +++ b/src/room_alias_id.rs @@ -7,13 +7,10 @@ use std::{ #[cfg(feature = "diesel")] use diesel::sql_types::Text; -use serde::{ - de::{Error as SerdeError, Expected, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use url::Host; -use crate::{display, error::Error, parse_id}; +use crate::{deserialize_id, display, error::Error, parse_id}; /// A Matrix room alias ID. /// @@ -80,10 +77,7 @@ impl<'de> Deserialize<'de> for RoomAliasId { where D: Deserializer<'de>, { - String::deserialize(deserializer).and_then(|v| { - RoomAliasId::try_from(&v as &str) - .map_err(|_| SerdeError::invalid_value(Unexpected::Str(&v), &ExpectedRoomAliasId)) - }) + deserialize_id(deserializer, "a Matrix room alias ID as a string") } } @@ -105,14 +99,6 @@ impl<'a> TryFrom<&'a str> for RoomAliasId { } } -struct ExpectedRoomAliasId; - -impl Expected for ExpectedRoomAliasId { - fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult { - write!(formatter, "a Matrix room alias ID as a string") - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom; diff --git a/src/room_id.rs b/src/room_id.rs index 09de6ca2..8c17bfb7 100644 --- a/src/room_id.rs +++ b/src/room_id.rs @@ -7,13 +7,10 @@ use std::{ #[cfg(feature = "diesel")] use diesel::sql_types::Text; -use serde::{ - de::{Error as SerdeError, Expected, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use url::Host; -use crate::{display, error::Error, generate_localpart, parse_id}; +use crate::{deserialize_id, display, error::Error, generate_localpart, parse_id}; /// A Matrix room ID. /// @@ -95,10 +92,7 @@ impl<'de> Deserialize<'de> for RoomId { where D: Deserializer<'de>, { - String::deserialize(deserializer).and_then(|v| { - RoomId::try_from(&v as &str) - .map_err(|_| SerdeError::invalid_value(Unexpected::Str(&v), &ExpectedRoomId)) - }) + deserialize_id(deserializer, "a Matrix room ID as a string") } } @@ -120,14 +114,6 @@ impl<'a> TryFrom<&'a str> for RoomId { } } -struct ExpectedRoomId; - -impl Expected for ExpectedRoomId { - fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult { - write!(formatter, "a Matrix room ID as a string") - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom; diff --git a/src/room_id_or_room_alias_id.rs b/src/room_id_or_room_alias_id.rs index f453131b..687cf3e1 100644 --- a/src/room_id_or_room_alias_id.rs +++ b/src/room_id_or_room_alias_id.rs @@ -7,12 +7,11 @@ use std::{ #[cfg(feature = "diesel")] use diesel::sql_types::Text; -use serde::{ - de::{Error as SerdeError, Expected, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::{display, error::Error, room_alias_id::RoomAliasId, room_id::RoomId, validate_id}; +use crate::{ + deserialize_id, display, error::Error, room_alias_id::RoomAliasId, room_id::RoomId, validate_id, +}; /// A Matrix room ID or a Matrix room alias ID. /// @@ -83,11 +82,10 @@ impl<'de> Deserialize<'de> for RoomIdOrAliasId { where D: Deserializer<'de>, { - String::deserialize(deserializer).and_then(|v| { - RoomIdOrAliasId::try_from(&v as &str).map_err(|_| { - SerdeError::invalid_value(Unexpected::Str(&v), &ExpectedRoomIdOrAliasId) - }) - }) + deserialize_id( + deserializer, + "a Matrix room ID or room alias ID as a string", + ) } } @@ -120,14 +118,6 @@ impl<'a> TryFrom<&'a str> for RoomIdOrAliasId { } } -struct ExpectedRoomIdOrAliasId; - -impl Expected for ExpectedRoomIdOrAliasId { - fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult { - write!(formatter, "a Matrix room ID or room alias ID as a string") - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom; diff --git a/src/room_version_id.rs b/src/room_version_id.rs index 44b59c2a..6277199b 100644 --- a/src/room_version_id.rs +++ b/src/room_version_id.rs @@ -7,12 +7,9 @@ use std::{ #[cfg(feature = "diesel")] use diesel::sql_types::Text; -use serde::{ - de::{Error as SerdeError, Expected, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use crate::error::Error; +use crate::{deserialize_id, error::Error}; /// Room version identifiers cannot be more than 32 code points. const MAX_CODE_POINTS: usize = 32; @@ -154,10 +151,7 @@ impl<'de> Deserialize<'de> for RoomVersionId { where D: Deserializer<'de>, { - String::deserialize(deserializer).and_then(|v| { - RoomVersionId::try_from(&v as &str) - .map_err(|_| SerdeError::invalid_value(Unexpected::Str(&v), &ExpectedRoomVersionId)) - }) + deserialize_id(deserializer, "a Matrix room version ID as a string") } } @@ -187,14 +181,6 @@ impl<'a> TryFrom<&'a str> for RoomVersionId { } } -struct ExpectedRoomVersionId; - -impl Expected for ExpectedRoomVersionId { - fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult { - write!(formatter, "a Matrix room version ID as a string") - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom; diff --git a/src/user_id.rs b/src/user_id.rs index 005ecf21..c0e415d8 100644 --- a/src/user_id.rs +++ b/src/user_id.rs @@ -7,13 +7,10 @@ use std::{ #[cfg(feature = "diesel")] use diesel::sql_types::Text; -use serde::{ - de::{Error as SerdeError, Expected, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, -}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use url::Host; -use crate::{display, error::Error, generate_localpart, parse_id}; +use crate::{deserialize_id, display, error::Error, generate_localpart, parse_id}; /// A Matrix user ID. /// @@ -99,10 +96,7 @@ impl<'de> Deserialize<'de> for UserId { where D: Deserializer<'de>, { - String::deserialize(deserializer).and_then(|v| { - UserId::try_from(&v as &str) - .map_err(|_| SerdeError::invalid_value(Unexpected::Str(&v), &ExpectedUserId)) - }) + deserialize_id(deserializer, "a Matrix user ID as a string") } } @@ -133,14 +127,6 @@ impl<'a> TryFrom<&'a str> for UserId { } } -struct ExpectedUserId; - -impl Expected for ExpectedUserId { - fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult { - write!(formatter, "a Matrix user ID as a string") - } -} - #[cfg(test)] mod tests { use std::convert::TryFrom;