common: Move CanonicalJson out of serde mod and behind a Cargo feature

This commit is contained in:
Jonas Platte 2022-06-17 18:50:36 +02:00 committed by Jonas Platte
parent e96b197d4d
commit 402b2764fb
10 changed files with 46 additions and 34 deletions

View File

@ -17,6 +17,8 @@ Breaking changes:
* Room name size limits were never enforced by servers
([Spec change removing the size limit][spec])
* Remove `RoomMessageFeedbackEvent` and associated types and variants according to MSC3582
* Move `CanonicalJson`, `CanonicalJsonObject` and `CanonicalJsonError` out of
the `serde` module and behind the cargo feature flag `canonical-json`
[spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/3669

View File

@ -22,6 +22,7 @@ client = []
server = []
api = ["http", "thiserror"]
canonical-json = []
compat = ["ruma-macros/compat", "ruma-identifiers-validation/compat"]
events = ["thiserror"]
js = ["js-sys", "getrandom?/js", "uuid?/js"]

View File

@ -1,16 +1,19 @@
//! Canonical JSON types and related functions.
use std::fmt;
use serde::Serialize;
use serde_json::{Error as JsonError, Value as JsonValue};
pub mod value;
mod value;
use value::Object as CanonicalJsonObject;
pub use self::value::{CanonicalJsonObject, CanonicalJsonValue};
/// The set of possible errors when serializing to canonical JSON.
#[cfg(feature = "canonical-json")]
#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum Error {
pub enum CanonicalJsonError {
/// The numeric value failed conversion to js_int::Int.
IntConvert,
@ -18,27 +21,31 @@ pub enum Error {
SerDe(JsonError),
}
impl fmt::Display for Error {
impl fmt::Display for CanonicalJsonError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::IntConvert => f.write_str("number found is not a valid `js_int::Int`"),
Error::SerDe(err) => write!(f, "serde Error: {err}"),
CanonicalJsonError::IntConvert => {
f.write_str("number found is not a valid `js_int::Int`")
}
CanonicalJsonError::SerDe(err) => write!(f, "serde Error: {err}"),
}
}
}
impl std::error::Error for Error {}
impl std::error::Error for CanonicalJsonError {}
/// Fallible conversion from a `serde_json::Map` to a `CanonicalJsonObject`.
pub fn try_from_json_map(
json: serde_json::Map<String, JsonValue>,
) -> Result<CanonicalJsonObject, Error> {
) -> Result<CanonicalJsonObject, CanonicalJsonError> {
json.into_iter().map(|(k, v)| Ok((k, v.try_into()?))).collect()
}
/// Fallible conversion from any value that impl's `Serialize` to a `CanonicalJsonValue`.
pub fn to_canonical_value<T: Serialize>(value: T) -> Result<value::CanonicalJsonValue, Error> {
serde_json::to_value(value).map_err(Error::SerDe)?.try_into()
pub fn to_canonical_value<T: Serialize>(
value: T,
) -> Result<value::CanonicalJsonValue, CanonicalJsonError> {
serde_json::to_value(value).map_err(CanonicalJsonError::SerDe)?.try_into()
}
#[cfg(test)]

View File

@ -4,12 +4,14 @@ use js_int::Int;
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
use serde_json::{to_string as to_json_string, Value as JsonValue};
use super::Error;
use super::CanonicalJsonError;
/// The inner type of `CanonicalJsonValue::Object`.
pub type Object = BTreeMap<String, CanonicalJsonValue>;
#[cfg(feature = "canonical-json")]
pub type CanonicalJsonObject = BTreeMap<String, CanonicalJsonValue>;
/// Represents a canonical JSON value as per the Matrix specification.
#[cfg(feature = "canonical-json")]
#[derive(Clone, Eq, PartialEq)]
#[allow(clippy::exhaustive_enums)]
pub enum CanonicalJsonValue {
@ -67,7 +69,7 @@ pub enum CanonicalJsonValue {
/// # use ruma_common::serde::CanonicalJsonValue;
/// let v: CanonicalJsonValue = json!({ "an": "object" }).try_into().unwrap();
/// ```
Object(Object),
Object(CanonicalJsonObject),
}
impl CanonicalJsonValue {
@ -104,7 +106,7 @@ impl CanonicalJsonValue {
}
/// If the `CanonicalJsonValue` is an `Object`, return a reference to the inner value.
pub fn as_object(&self) -> Option<&Object> {
pub fn as_object(&self) -> Option<&CanonicalJsonObject> {
match self {
Self::Object(o) => Some(o),
_ => None,
@ -120,7 +122,7 @@ impl CanonicalJsonValue {
}
/// If the `CanonicalJsonValue` is an `Object`, return a mutable reference to the inner value.
pub fn as_object_mut(&mut self) -> Option<&mut Object> {
pub fn as_object_mut(&mut self) -> Option<&mut CanonicalJsonObject> {
match self {
Self::Object(o) => Some(o),
_ => None,
@ -195,14 +197,14 @@ impl fmt::Display for CanonicalJsonValue {
}
impl TryFrom<JsonValue> for CanonicalJsonValue {
type Error = Error;
type Error = CanonicalJsonError;
fn try_from(val: JsonValue) -> Result<Self, Self::Error> {
Ok(match val {
JsonValue::Bool(b) => Self::Bool(b),
JsonValue::Number(num) => Self::Integer(
Int::try_from(num.as_i64().ok_or(Error::IntConvert)?)
.map_err(|_| Error::IntConvert)?,
Int::try_from(num.as_i64().ok_or(CanonicalJsonError::IntConvert)?)
.map_err(|_| CanonicalJsonError::IntConvert)?,
),
JsonValue::Array(vec) => {
Self::Array(vec.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?)
@ -211,7 +213,7 @@ impl TryFrom<JsonValue> for CanonicalJsonValue {
JsonValue::Object(obj) => Self::Object(
obj.into_iter()
.map(|(k, v)| Ok((k, v.try_into()?)))
.collect::<Result<Object, _>>()?,
.collect::<Result<CanonicalJsonObject, _>>()?,
),
JsonValue::Null => Self::Null,
})
@ -267,7 +269,7 @@ variant_impls!(Bool(bool));
variant_impls!(Integer(Int));
variant_impls!(String(String));
variant_impls!(Array(Vec<CanonicalJsonValue>));
variant_impls!(Object(Object));
variant_impls!(Object(CanonicalJsonObject));
impl Serialize for CanonicalJsonValue {
#[inline]

View File

@ -25,6 +25,8 @@ extern crate self as ruma_common;
#[cfg(feature = "api")]
pub mod api;
pub mod authentication;
#[cfg(feature = "canonical-json")]
pub mod canonical_json;
pub mod directory;
pub mod encryption;
#[cfg(feature = "events")]
@ -42,8 +44,12 @@ pub mod to_device;
use std::fmt;
pub use identifiers::*;
pub use time::{MilliSecondsSinceUnixEpoch, SecondsSinceUnixEpoch};
#[cfg(feature = "canonical-json")]
pub use self::canonical_json::{CanonicalJsonError, CanonicalJsonObject, CanonicalJsonValue};
pub use self::{
identifiers::*,
time::{MilliSecondsSinceUnixEpoch, SecondsSinceUnixEpoch},
};
// Wrapper around `Box<str>` that cannot be used in a meaningful way outside of
// this crate. Used for string enums because their `_Custom` variant can't be

View File

@ -11,7 +11,6 @@ use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
pub mod base64;
mod buf;
pub mod can_be_empty;
mod canonical_json;
mod cow;
pub mod duration;
mod empty;
@ -26,11 +25,6 @@ pub use self::{
base64::{Base64, Base64DecodeError},
buf::{json_to_buf, slice_to_buf},
can_be_empty::{is_empty, CanBeEmpty},
canonical_json::{
to_canonical_value, try_from_json_map,
value::{CanonicalJsonValue, Object as CanonicalJsonObject},
Error as CanonicalJsonError,
},
cow::deserialize_cow_str,
empty::vec_as_map_of_empty,
raw::Raw,

View File

@ -25,7 +25,7 @@ ed25519-dalek = "1.0.1"
pkcs8 = { version = "0.9.0", features = ["alloc"] }
# because dalek uses an older version of rand_core
rand = { version = "0.7", features = ["getrandom"] }
ruma-common = { version = "0.9.2", path = "../ruma-common" }
ruma-common = { version = "0.9.2", path = "../ruma-common", features = ["canonical-json"] }
serde_json = "1.0.60"
sha2 = "0.9.5"
subslice = { version = "0.2.3", optional = true }

View File

@ -8,8 +8,8 @@ use std::{
use base64::{encode_config, STANDARD_NO_PAD, URL_SAFE_NO_PAD};
use ruma_common::{
serde::{base64::Standard, Base64, CanonicalJsonObject, CanonicalJsonValue},
OwnedEventId, OwnedServerName, RoomVersionId, UserId,
serde::{base64::Standard, Base64},
CanonicalJsonObject, CanonicalJsonValue, OwnedEventId, OwnedServerName, RoomVersionId, UserId,
};
use serde_json::{from_str as from_json_str, to_string as to_json_string};
use sha2::{digest::Digest, Sha256};
@ -881,8 +881,7 @@ mod tests {
use assert_matches::assert_matches;
use ruma_common::{
serde::{Base64, CanonicalJsonValue},
RoomVersionId, ServerSigningKeyId, SigningKeyAlgorithm,
serde::Base64, CanonicalJsonValue, RoomVersionId, ServerSigningKeyId, SigningKeyAlgorithm,
};
use serde_json::json;

View File

@ -52,7 +52,7 @@ pub use functions::{
redact_in_place, reference_hash, sign_json, verify_event, verify_json,
};
pub use keys::{Ed25519KeyPair, KeyPair, PublicKeyMap, PublicKeySet};
pub use ruma_common::serde::{CanonicalJsonError, CanonicalJsonObject, CanonicalJsonValue};
pub use ruma_common::{CanonicalJsonError, CanonicalJsonObject, CanonicalJsonValue};
pub use signatures::Signature;
pub use verification::Verified;

View File

@ -17,6 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[features]
api = ["ruma-common/api"]
canonical-json = ["ruma-common/canonical-json"]
client = ["ruma-client"]
events = ["ruma-common/events"]
signatures = ["ruma-signatures"]