Update ruma_serde to 0.1.2

This commit is contained in:
Jonas Platte 2020-04-30 18:07:20 +02:00
parent fd5527da78
commit 0d305d8f24
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
14 changed files with 30 additions and 170 deletions

View File

@ -16,7 +16,7 @@ edition = "2018"
js_int = { version = "0.1.5", features = ["serde"] } js_int = { version = "0.1.5", features = ["serde"] }
ruma-events-macros = { path = "ruma-events-macros", version = "=0.21.0-beta.1" } ruma-events-macros = { path = "ruma-events-macros", version = "=0.21.0-beta.1" }
ruma-identifiers = "0.16.0" ruma-identifiers = "0.16.0"
ruma-serde = "0.1.0" ruma-serde = "0.1.2"
serde = { version = "1.0.106", features = ["derive"] } serde = { version = "1.0.106", features = ["derive"] }
serde_json = { version = "1.0.52", features = ["raw_value"] } serde_json = { version = "1.0.52", features = ["raw_value"] }

View File

@ -64,10 +64,10 @@ impl From<Algorithm> for String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruma_serde::test::serde_json_eq;
use serde_json::json; use serde_json::json;
use super::*; use super::*;
use crate::util::serde_json_eq;
#[test] #[test]
fn serialize_and_deserialize_from_display_form() { fn serialize_and_deserialize_from_display_form() {

View File

@ -1,8 +1,7 @@
//! Types for the *m.dummy* event. //! Types for the *m.dummy* event.
use ruma_events_macros::ruma_event; use ruma_events_macros::ruma_event;
use ruma_serde::empty::Empty;
use crate::Empty;
ruma_event! { ruma_event! {
/// This event type is used to indicate new Olm sessions for end-to-end encryption. /// This event type is used to indicate new Olm sessions for end-to-end encryption.

View File

@ -1,58 +0,0 @@
use std::fmt::{self, Formatter};
use serde::{
de::{Deserialize, Deserializer, MapAccess, Visitor},
ser::{Serialize, SerializeMap, Serializer},
};
use crate::FromRaw;
/// A meaningless value that serializes to an empty JSON object.
///
/// This type is used in a few places where the Matrix specification requires an empty JSON object,
/// but it's wasteful to represent it as a `BTreeMap` in Rust code.
#[derive(Clone, Debug, PartialEq)]
pub struct Empty;
impl Serialize for Empty {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_map(Some(0))?.end()
}
}
impl<'de> Deserialize<'de> for Empty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct EmptyMapVisitor;
impl<'de> Visitor<'de> for EmptyMapVisitor {
type Value = Empty;
fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "an object/map")
}
fn visit_map<A>(self, _map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'de>,
{
Ok(Empty)
}
}
deserializer.deserialize_map(EmptyMapVisitor)
}
}
impl FromRaw for Empty {
type Raw = Self;
fn from_raw(raw: Self) -> Self {
raw
}
}

View File

@ -269,10 +269,10 @@ impl From<EventType> for String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruma_serde::test::serde_json_eq;
use serde_json::json; use serde_json::json;
use super::*; use super::*;
use crate::util::serde_json_eq;
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
#[test] #[test]

View File

@ -27,6 +27,14 @@ pub trait TryFromRaw: Sized {
fn try_from_raw(_: Self::Raw) -> Result<Self, Self::Err>; fn try_from_raw(_: Self::Raw) -> Result<Self, Self::Err>;
} }
impl FromRaw for ruma_serde::empty::Empty {
type Raw = Self;
fn from_raw(raw: Self) -> Self {
raw
}
}
impl FromRaw for serde_json::Value { impl FromRaw for serde_json::Value {
type Raw = Self; type Raw = Self;

View File

@ -3,7 +3,7 @@
use ruma_identifiers::UserId; use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{util::vec_as_map_of_empty, EventType, FromRaw}; use crate::{EventType, FromRaw};
/// A list of users to ignore. /// A list of users to ignore.
#[derive(Clone, Debug, PartialEq, Serialize)] #[derive(Clone, Debug, PartialEq, Serialize)]
@ -27,7 +27,7 @@ impl FromRaw for IgnoredUserListEvent {
#[derive(Clone, Debug, PartialEq, Serialize)] #[derive(Clone, Debug, PartialEq, Serialize)]
pub struct IgnoredUserListEventContent { pub struct IgnoredUserListEventContent {
/// A list of users to ignore. /// A list of users to ignore.
#[serde(with = "vec_as_map_of_empty")] #[serde(with = "ruma_serde::vec_as_map_of_empty")]
pub ignored_users: Vec<UserId>, pub ignored_users: Vec<UserId>,
} }
@ -61,7 +61,7 @@ pub(crate) mod raw {
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IgnoredUserListEventContent { pub struct IgnoredUserListEventContent {
/// A list of users to ignore. /// A list of users to ignore.
#[serde(with = "vec_as_map_of_empty")] #[serde(with = "ruma_serde::vec_as_map_of_empty")]
pub ignored_users: Vec<UserId>, pub ignored_users: Vec<UserId>,
} }
} }

View File

@ -122,16 +122,15 @@ use serde::{Deserialize, Serialize};
use self::room::redaction::RedactionEvent; use self::room::redaction::RedactionEvent;
pub use self::{ pub use self::custom::{CustomEvent, CustomRoomEvent, CustomStateEvent};
custom::{CustomEvent, CustomRoomEvent, CustomStateEvent},
empty::Empty, #[deprecated = "Use ruma_serde::empty::Empty directly instead."]
}; pub use ruma_serde::empty::Empty;
#[macro_use] #[macro_use]
mod macros; mod macros;
mod algorithm; mod algorithm;
mod empty;
mod error; mod error;
mod event_type; mod event_type;
mod from_raw; mod from_raw;

View File

@ -13,7 +13,7 @@ use serde::{
}; };
use serde_json::{from_value, Value}; use serde_json::{from_value, Value};
use crate::{util::default_true, FromStrError}; use crate::FromStrError;
ruma_event! { ruma_event! {
/// Describes all push rules for a user. /// Describes all push rules for a user.
@ -230,13 +230,12 @@ impl<'de> Deserialize<'de> for Action {
/// Values for the `set_tweak` action. /// Values for the `set_tweak` action.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[serde(tag = "set_tweak")] #[serde(tag = "set_tweak", rename_all = "lowercase")]
pub enum Tweak { pub enum Tweak {
/// A string representing the sound to be played when this notification arrives. /// A string representing the sound to be played when this notification arrives.
/// ///
/// A value of "default" means to play a default sound. A device may choose to alert the user by /// A value of "default" means to play a default sound. A device may choose to alert the user by
/// some other means if appropriate, eg. vibration. /// some other means if appropriate, eg. vibration.
#[serde(rename = "sound")]
Sound { Sound {
/// The sound to be played. /// The sound to be played.
value: String, value: String,
@ -249,10 +248,9 @@ pub enum Tweak {
/// event occurred. If a `highlight` tweak is given with no value, its value is defined to be /// event occurred. If a `highlight` tweak is given with no value, its value is defined to be
/// `true`. If no highlight tweak is given at all then the value of `highlight` is defined to be /// `true`. If no highlight tweak is given at all then the value of `highlight` is defined to be
/// `false`. /// `false`.
#[serde(rename = "highlight")]
Highlight { Highlight {
/// Whether or not the message should be highlighted. /// Whether or not the message should be highlighted.
#[serde(default = "default_true")] #[serde(default = "ruma_serde::default_true")]
value: bool, value: bool,
}, },
} }

View File

@ -3,8 +3,6 @@
use ruma_events_macros::ruma_event; use ruma_events_macros::ruma_event;
use ruma_identifiers::RoomAliasId; use ruma_identifiers::RoomAliasId;
use crate::util::empty_string_as_none;
ruma_event! { ruma_event! {
/// Informs the room as to which alias is the canonical one. /// Informs the room as to which alias is the canonical one.
CanonicalAliasEvent { CanonicalAliasEvent {
@ -16,7 +14,7 @@ ruma_event! {
/// Rooms with `alias: None` should be treated the same as a room /// Rooms with `alias: None` should be treated the same as a room
/// with no canonical alias. /// with no canonical alias.
#[serde( #[serde(
default, deserialize_with = "empty_string_as_none", default, deserialize_with = "ruma_serde::empty_string_as_none",
skip_serializing_if = "Option::is_none" skip_serializing_if = "Option::is_none"
)] )]
pub alias: Option<RoomAliasId>, pub alias: Option<RoomAliasId>,

View File

@ -6,8 +6,6 @@ use ruma_events_macros::ruma_event;
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId}; use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::util::default_true;
ruma_event! { ruma_event! {
/// This is the first event in a room and cannot be changed. It acts as the root of all other /// This is the first event in a room and cannot be changed. It acts as the root of all other
/// events. /// events.
@ -19,8 +17,7 @@ ruma_event! {
pub creator: UserId, pub creator: UserId,
/// Whether or not this room's data should be transferred to other homeservers. /// Whether or not this room's data should be transferred to other homeservers.
#[serde(rename = "m.federate")] #[serde(rename = "m.federate", default = "ruma_serde::default_true")]
#[serde(default = "default_true")]
pub federate: bool, pub federate: bool,
/// The version of the room. Defaults to "1" if the key does not exist. /// The version of the room. Defaults to "1" if the key does not exist.

View File

@ -5,7 +5,7 @@ use std::time::SystemTime;
use ruma_identifiers::{EventId, RoomId, UserId}; use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{util::empty_string_as_none, EventType, InvalidInput, TryFromRaw, UnsignedData}; use crate::{EventType, InvalidInput, TryFromRaw, UnsignedData};
/// A human-friendly room name designed to be displayed to the end-user. /// A human-friendly room name designed to be displayed to the end-user.
#[derive(Clone, Debug, PartialEq, Serialize)] #[derive(Clone, Debug, PartialEq, Serialize)]
@ -144,8 +144,7 @@ pub(crate) mod raw {
/// The name of the room. This MUST NOT exceed 255 bytes. /// The name of the room. This MUST NOT exceed 255 bytes.
// The spec says "A room with an m.room.name event with an absent, null, or empty name field // The spec says "A room with an m.room.name event with an absent, null, or empty name field
// should be treated the same as a room with no m.room.name event." // should be treated the same as a room with no m.room.name event."
#[serde(default)] #[serde(default, deserialize_with = "ruma_serde::empty_string_as_none")]
#[serde(deserialize_with = "empty_string_as_none")]
pub(crate) name: Option<String>, pub(crate) name: Option<String>,
} }
} }

View File

@ -5,7 +5,7 @@ use std::time::SystemTime;
use ruma_identifiers::{EventId, RoomId, UserId}; use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{util::default_true, EventType, FromRaw, UnsignedData}; use crate::{EventType, FromRaw, UnsignedData};
/// An event to indicate which servers are permitted to participate in the room. /// An event to indicate which servers are permitted to participate in the room.
#[derive(Clone, Debug, PartialEq, Serialize)] #[derive(Clone, Debug, PartialEq, Serialize)]
@ -49,7 +49,7 @@ pub struct ServerAclEventContent {
/// This is strongly recommended to be set to false as servers running with IP literal names are /// This is strongly recommended to be set to false as servers running with IP literal names are
/// strongly discouraged in order to require legitimate homeservers to be backed by a valid /// strongly discouraged in order to require legitimate homeservers to be backed by a valid
/// registered domain name. /// registered domain name.
#[serde(default = "default_true")] #[serde(default = "ruma_serde::default_true")]
pub allow_ip_literals: bool, pub allow_ip_literals: bool,
/// The server names to allow in the room, excluding any port information. Wildcards may be used /// The server names to allow in the room, excluding any port information. Wildcards may be used
@ -146,7 +146,7 @@ pub(crate) mod raw {
/// This is strongly recommended to be set to false as servers running with IP literal names /// This is strongly recommended to be set to false as servers running with IP literal names
/// are strongly discouraged in order to require legitimate homeservers to be backed by a /// are strongly discouraged in order to require legitimate homeservers to be backed by a
/// valid registered domain name. /// valid registered domain name.
#[serde(default = "default_true")] #[serde(default = "ruma_serde::default_true")]
pub allow_ip_literals: bool, pub allow_ip_literals: bool,
/// The server names to allow in the room, excluding any port information. Wildcards may be /// The server names to allow in the room, excluding any port information. Wildcards may be

View File

@ -1,9 +1,6 @@
use std::fmt::Debug; use std::fmt::Debug;
use serde::{ use serde::{de::DeserializeOwned, Serialize};
de::{Deserialize, DeserializeOwned, IntoDeserializer},
Serialize,
};
use serde_json::Value; use serde_json::Value;
use crate::{EventJson, TryFromRaw}; use crate::{EventJson, TryFromRaw};
@ -45,83 +42,6 @@ where
.map_err(serde_json_error_to_generic_de_error) .map_err(serde_json_error_to_generic_de_error)
} }
/// Serde deserialization decorator to map empty Strings to None,
/// and forward non-empty Strings to the Deserialize implementation for T.
/// Useful for the typical
/// "A room with an X event with an absent, null, or empty Y field
/// should be treated the same as a room with no such event."
/// formulation in the spec.
///
/// To be used like this:
/// `#[serde(deserialize_with = "empty_string_as_none"]`
/// Relevant serde issue: https://github.com/serde-rs/serde/issues/1425
pub fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: serde::Deserialize<'de>,
{
let opt = Option::<String>::deserialize(de)?;
// TODO: Switch to and remove this attribute `opt.as_deref()` once MSRV is >= 1.40
#[allow(clippy::option_as_ref_deref, clippy::unknown_clippy_lints)]
let opt = opt.as_ref().map(String::as_str);
match opt {
None | Some("") => Ok(None),
// If T = String, like in m.room.name, the second deserialize is actually superfluous.
// TODO: optimize that somehow?
Some(s) => T::deserialize(s.into_deserializer()).map(Some),
}
}
/// Serde serialization and deserialization functions that map a `Vec<T>` to a `BTreeMap<T, Empty>`.
///
/// The Matrix spec sometimes specifies lists as hash maps so the list entries can be expanded with
/// attributes without breaking compatibility. As that would be a breaking change for ruma's event
/// types anyway, we convert them to `Vec`s for simplicity, using this module.
///
/// To be used as `#[serde(with = "vec_as_map_of_empty")]`.
pub mod vec_as_map_of_empty {
use std::collections::BTreeMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::Empty;
#[allow(clippy::ptr_arg)]
pub fn serialize<S, T>(vec: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Serialize + Eq + Ord,
{
vec.iter()
.map(|v| (v, Empty))
.collect::<BTreeMap<_, _>>()
.serialize(serializer)
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Eq + Ord,
{
BTreeMap::<T, Empty>::deserialize(deserializer)
.map(|hashmap| hashmap.into_iter().map(|(k, _)| k).collect())
}
}
/// Used to default the `bool` fields to `true` during deserialization.
pub fn default_true() -> bool {
true
}
#[cfg(test)]
pub fn serde_json_eq<T>(de: T, se: serde_json::Value)
where
T: Clone + Debug + PartialEq + Serialize + DeserializeOwned,
{
assert_eq!(se, serde_json::to_value(de.clone()).unwrap());
assert_eq!(de, serde_json::from_value(se).unwrap());
}
// This would be #[cfg(test)] if it wasn't used from external tests // This would be #[cfg(test)] if it wasn't used from external tests
pub fn serde_json_eq_try_from_raw<T>(de: T, se: serde_json::Value) pub fn serde_json_eq_try_from_raw<T>(de: T, se: serde_json::Value)
where where