events: Move ignored_users serde code into ignored_user_list module

… and optimize it.
This commit is contained in:
Jonas Platte 2022-09-24 11:18:06 +02:00
parent 289821aa07
commit ac707e30f0
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
4 changed files with 87 additions and 77 deletions

View File

@ -4,6 +4,7 @@ Breaking changes:
* Remove deprecated `EventType` enum
* Remove deprecated constructors for `RoomMessageEventContent`
* Remove `serde::vec_as_map_of_empty` from the public API
# 0.10.3

View File

@ -15,7 +15,7 @@ use crate::OwnedUserId;
#[ruma_event(type = "m.ignored_user_list", kind = GlobalAccountData)]
pub struct IgnoredUserListEventContent {
/// A list of users to ignore.
#[serde(with = "crate::serde::vec_as_map_of_empty")]
#[serde(with = "vec_as_map_of_empty")]
pub ignored_users: Vec<OwnedUserId>,
}
@ -26,6 +26,91 @@ impl IgnoredUserListEventContent {
}
}
mod vec_as_map_of_empty {
use std::{fmt, marker::PhantomData};
use serde::{
de::{self, Deserialize, Deserializer},
ser::{SerializeMap, Serializer},
Serialize,
};
/// Serialize the given `Vec<T>` as a map of `T => 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,
{
let mut map = serializer.serialize_map(Some(vec.len()))?;
for item in vec {
map.serialize_entry(item, &Empty {})?;
}
map.end()
}
/// Deserialize an object and return the keys as a `Vec<T>`.
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Eq + Ord,
{
struct MapOfEmptyVisitor<T>(PhantomData<T>);
impl<'de, T> de::Visitor<'de> for MapOfEmptyVisitor<T>
where
T: Deserialize<'de>,
{
type Value = Vec<T>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "an object/map")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
let mut items = Vec::with_capacity(map.size_hint().unwrap_or(0));
while let Some((item, _)) = map.next_entry::<T, Empty>()? {
items.push(item);
}
Ok(items)
}
}
deserializer.deserialize_map(MapOfEmptyVisitor(PhantomData))
}
#[derive(Clone, Debug, Serialize)]
struct Empty {}
impl<'de> Deserialize<'de> for Empty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct EmptyMapVisitor;
impl<'de> de::Visitor<'de> for EmptyMapVisitor {
type Value = Empty;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "an object/map")
}
fn visit_map<A>(self, _map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
Ok(Empty {})
}
}
deserializer.deserialize_map(EmptyMapVisitor)
}
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;

View File

@ -13,7 +13,6 @@ mod buf;
pub mod can_be_empty;
mod cow;
pub mod duration;
mod empty;
pub mod json_string;
mod raw;
pub mod single_element_seq;
@ -26,7 +25,6 @@ pub use self::{
buf::{json_to_buf, slice_to_buf},
can_be_empty::{is_empty, CanBeEmpty},
cow::deserialize_cow_str,
empty::vec_as_map_of_empty,
raw::Raw,
strings::{
btreemap_deserialize_v1_powerlevel_values, deserialize_v1_powerlevel, empty_string_as_none,

View File

@ -1,74 +0,0 @@
use std::fmt;
use serde::{
de::{self, Deserialize},
Serialize,
};
#[derive(Clone, Debug, Serialize)]
pub struct Empty {}
impl<'de> Deserialize<'de> for Empty {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct EmptyMapVisitor;
impl<'de> de::Visitor<'de> for EmptyMapVisitor {
type Value = Empty;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "an object/map")
}
fn visit_map<A>(self, _map: A) -> Result<Self::Value, A::Error>
where
A: de::MapAccess<'de>,
{
Ok(Empty {})
}
}
deserializer.deserialize_map(EmptyMapVisitor)
}
}
/// 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 super::Empty;
/// Serialize the given `Vec<T>` as a map of `T => 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,
{
// FIXME: Don't construct a temporary `BTreeMap`.
vec.iter().map(|v| (v, Empty {})).collect::<BTreeMap<_, _>>().serialize(serializer)
}
/// Deserialize an object and return the keys as a `Vec<T>`.
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Eq + Ord,
{
// FIXME: Don't construct a temporary `BTreeMap`.
BTreeMap::<T, Empty>::deserialize(deserializer)
.map(|hashmap| hashmap.into_iter().map(|(k, _)| k).collect())
}
}