Move (de)serialization helpers to util module
This commit is contained in:
parent
777f3b9686
commit
665fe4f4f4
@ -3,7 +3,7 @@
|
||||
use ruma_identifiers::UserId;
|
||||
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
||||
|
||||
use crate::{vec_as_map_of_empty, Event as _, EventType, FromRaw};
|
||||
use crate::{util::vec_as_map_of_empty, Event as _, EventType, FromRaw};
|
||||
|
||||
/// A list of users to ignore.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
66
src/lib.rs
66
src/lib.rs
@ -123,7 +123,7 @@ use std::{
|
||||
use js_int::UInt;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde::{
|
||||
de::{DeserializeOwned, Error as SerdeError, IntoDeserializer, MapAccess, Visitor},
|
||||
de::{DeserializeOwned, Error as SerdeError, MapAccess, Visitor},
|
||||
ser::SerializeMap,
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
@ -853,70 +853,6 @@ impl<'de> Deserialize<'de> for Algorithm {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
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)?;
|
||||
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 `HashMap<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")]`.
|
||||
mod vec_as_map_of_empty {
|
||||
use super::Empty;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn serialize<S, T>(vec: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
T: Serialize + Hash + Eq,
|
||||
{
|
||||
vec.iter()
|
||||
.map(|v| (v, Empty))
|
||||
.collect::<HashMap<_, _>>()
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Hash + Eq,
|
||||
{
|
||||
HashMap::<T, Empty>::deserialize(deserializer)
|
||||
.map(|hashmap| hashmap.into_iter().map(|(k, _)| k).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to default the `bool` fields to `true` during deserialization.
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::{from_str, to_string};
|
||||
|
@ -12,7 +12,7 @@ use serde::{
|
||||
};
|
||||
use serde_json::{from_value, Value};
|
||||
|
||||
use super::{default_true, FromStrError};
|
||||
use crate::{util::default_true, FromStrError};
|
||||
|
||||
ruma_event! {
|
||||
/// Describes all push rules for a user.
|
||||
|
@ -5,7 +5,7 @@ use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
|
||||
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{empty_string_as_none, Event, EventType, FromRaw};
|
||||
use crate::{util::empty_string_as_none, Event, EventType, FromRaw};
|
||||
|
||||
/// Informs the room as to which alias is the canonical one.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -6,7 +6,7 @@ use ruma_events_macros::ruma_event;
|
||||
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::default_true;
|
||||
use crate::util::default_true;
|
||||
|
||||
ruma_event! {
|
||||
/// This is the first event in a room and cannot be changed. It acts as the root of all other
|
||||
|
@ -5,7 +5,7 @@ use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{empty_string_as_none, Event as _, EventType, FromRaw, InvalidInput};
|
||||
use crate::{util::empty_string_as_none, Event as _, EventType, FromRaw, InvalidInput};
|
||||
|
||||
/// A human-friendly room name designed to be displayed to the end-user.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -5,7 +5,7 @@ use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{default_true, Event as _, EventType, FromRaw};
|
||||
use crate::{util::default_true, Event as _, EventType, FromRaw};
|
||||
|
||||
/// An event to indicate which servers are permitted to participate in the room.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
66
src/util.rs
66
src/util.rs
@ -1,4 +1,4 @@
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::de::{Deserialize, DeserializeOwned, IntoDeserializer};
|
||||
|
||||
use crate::TryFromRaw;
|
||||
|
||||
@ -28,3 +28,67 @@ pub fn get_field<T: DeserializeOwned, E: serde::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)?;
|
||||
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 `HashMap<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 crate::Empty;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::{collections::HashMap, hash::Hash};
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
pub fn serialize<S, T>(vec: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
T: Serialize + Hash + Eq,
|
||||
{
|
||||
vec.iter()
|
||||
.map(|v| (v, Empty))
|
||||
.collect::<HashMap<_, _>>()
|
||||
.serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Hash + Eq,
|
||||
{
|
||||
HashMap::<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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user