Improve Synapse compatibility w.r.t. power levels

This commit is contained in:
Jonathan de Jong 2022-02-01 15:26:30 +01:00 committed by GitHub
parent bdf4a86770
commit 8348b97091
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 27 deletions

View File

@ -13,7 +13,10 @@ pub struct NotificationPowerLevels {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default = "default_power_level")]
pub room: Int,
}

View File

@ -25,7 +25,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
#[ruma_event(skip_redaction)]
pub ban: Int,
@ -38,7 +41,7 @@ pub struct RoomPowerLevelsEventContent {
/// integers too.
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
serde(deserialize_with = "ruma_serde::btreemap_deserialize_v1_powerlevel_values")
)]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
#[ruma_event(skip_redaction)]
@ -48,7 +51,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default, skip_serializing_if = "ruma_serde::is_default")]
#[ruma_event(skip_redaction)]
pub events_default: Int,
@ -57,7 +63,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
pub invite: Int,
@ -65,7 +74,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
#[ruma_event(skip_redaction)]
pub kick: Int,
@ -74,7 +86,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
#[ruma_event(skip_redaction)]
pub redact: Int,
@ -83,7 +98,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default = "default_power_level", skip_serializing_if = "is_default_power_level")]
#[ruma_event(skip_redaction)]
pub state_default: Int,
@ -96,7 +114,7 @@ pub struct RoomPowerLevelsEventContent {
/// integers too.
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
serde(deserialize_with = "ruma_serde::btreemap_deserialize_v1_powerlevel_values")
)]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
#[ruma_event(skip_redaction)]
@ -106,7 +124,10 @@ pub struct RoomPowerLevelsEventContent {
///
/// If you activate the `compat` feature, deserialization will work for stringified
/// integers too.
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default, skip_serializing_if = "ruma_serde::is_default")]
#[ruma_event(skip_redaction)]
pub users_default: Int,

View File

@ -33,7 +33,7 @@ pub use self::{
empty::vec_as_map_of_empty,
raw::Raw,
strings::{
btreemap_int_or_string_to_int_values, empty_string_as_none, int_or_string_to_int,
btreemap_deserialize_v1_powerlevel_values, deserialize_v1_powerlevel, empty_string_as_none,
none_as_empty_string,
},
};

View File

@ -1,6 +1,6 @@
use std::{collections::BTreeMap, convert::TryInto, fmt, marker::PhantomData};
use js_int::Int;
use js_int::{Int, UInt};
use serde::{
de::{self, Deserializer, IntoDeserializer as _, MapAccess, Visitor},
ser::Serializer,
@ -52,8 +52,8 @@ where
/// Take either an integer number or a string and deserialize to an integer number.
///
/// To be used like this:
/// `#[serde(deserialize_with = "int_or_string_to_int")]`
pub fn int_or_string_to_int<'de, D>(de: D) -> Result<Int, D::Error>
/// `#[serde(deserialize_with = "deserialize_v1_powerlevel")]`
pub fn deserialize_v1_powerlevel<'de, D>(de: D) -> Result<Int, D::Error>
where
D: Deserializer<'de>,
{
@ -107,7 +107,12 @@ where
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
v.parse().map_err(E::custom)
let trimmed = v.trim();
match trimmed.strip_prefix('+') {
Some(without) => without.parse::<UInt>().map(|u| u.into()).map_err(E::custom),
None => trimmed.parse().map_err(E::custom),
}
}
}
@ -118,8 +123,10 @@ where
/// those to integer numbers.
///
/// To be used like this:
/// `#[serde(deserialize_with = "btreemap_int_or_string_to_int_values")]`
pub fn btreemap_int_or_string_to_int_values<'de, D, T>(de: D) -> Result<BTreeMap<T, Int>, D::Error>
/// `#[serde(deserialize_with = "btreemap_deserialize_v1_powerlevel_values")]`
pub fn btreemap_deserialize_v1_powerlevel_values<'de, D, T>(
de: D,
) -> Result<BTreeMap<T, Int>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Ord,
@ -132,7 +139,7 @@ where
where
D: Deserializer<'de>,
{
int_or_string_to_int(deserializer).map(IntWrap)
deserialize_v1_powerlevel(deserializer).map(IntWrap)
}
}
@ -176,16 +183,16 @@ mod tests {
use matches::assert_matches;
use serde::Deserialize;
use super::int_or_string_to_int;
use super::deserialize_v1_powerlevel;
#[test]
fn int_or_string() -> serde_json::Result<()> {
#[derive(Debug, Deserialize)]
struct Test {
#[serde(deserialize_with = "int_or_string_to_int")]
#[serde(deserialize_with = "deserialize_v1_powerlevel")]
num: Int,
}
#[test]
fn int_or_string() -> serde_json::Result<()> {
assert_matches!(
serde_json::from_value::<Test>(serde_json::json!({ "num": "0" }))?,
Test { num } if num == int!(0)
@ -193,4 +200,24 @@ mod tests {
Ok(())
}
#[test]
fn weird_plus_string() -> serde_json::Result<()> {
assert_matches!(
serde_json::from_value::<Test>(serde_json::json!({ "num": " +0000000001000 " }))?,
Test { num } if num == int!(1000)
);
Ok(())
}
#[test]
fn weird_minus_string() -> serde_json::Result<()> {
assert_matches!(
serde_json::from_value::<Test>(serde_json::json!({ "num": " \n\n-0000000000000001000 " }))?,
Test { num } if num == int!(-1000)
);
Ok(())
}
}

View File

@ -339,12 +339,15 @@ where
struct PowerLevelsContentFields {
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::btreemap_int_or_string_to_int_values")
serde(deserialize_with = "ruma_serde::btreemap_deserialize_v1_powerlevel_values")
)]
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
users: BTreeMap<Box<UserId>, Int>,
#[cfg_attr(feature = "compat", serde(deserialize_with = "ruma_serde::int_or_string_to_int"))]
#[cfg_attr(
feature = "compat",
serde(deserialize_with = "ruma_serde::deserialize_v1_powerlevel")
)]
#[serde(default, skip_serializing_if = "ruma_serde::is_default")]
users_default: Int,
}