Add free function to_canonical_json_string
and move the canonical JSON error type from the canonical_json::value module to canonical_json.
This commit is contained in:
parent
9dc92c31cf
commit
e795c7fcd6
@ -1 +1,98 @@
|
||||
use std::fmt;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde_json::Error as JsonError;
|
||||
|
||||
pub mod value;
|
||||
|
||||
/// Returns a canonical JSON string according to Matrix specification.
|
||||
///
|
||||
/// This function should be preferred over `serde_json::to_string` since it checks the size of the
|
||||
/// canonical string. Matrix canonical JSON enforces a size limit of less than 65,535 when sending
|
||||
/// PDU's for the server-server protocol.
|
||||
pub fn to_string<T: Serialize>(val: &T) -> Result<String, Error> {
|
||||
let s = serde_json::to_string(val).map_err(Error::SerDe)?;
|
||||
|
||||
if s.as_bytes().len() > 65_535 {
|
||||
Err(Error::JsonSize)
|
||||
} else {
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// The set of possible errors when serializing to canonical JSON.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The numeric value failed conversion to js_int::Int.
|
||||
IntConvert,
|
||||
/// The `CanonicalJsonValue` being serialized was larger than 65,535 bytes.
|
||||
JsonSize,
|
||||
/// An error occurred while serializing/deserializing.
|
||||
SerDe(JsonError),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
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::JsonSize => f.write_str("JSON is larger than 65,535 byte max"),
|
||||
Error::SerDe(err) => write!(f, "serde Error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::convert::TryInto;
|
||||
|
||||
use super::{to_string as to_canonical_json_string, value::CanonicalJsonValue};
|
||||
use serde_json::{from_str as from_json_str, json, to_string as to_json_string};
|
||||
|
||||
#[test]
|
||||
fn serialize_canon() {
|
||||
let json: CanonicalJsonValue = json!({
|
||||
"a": [1, 2, 3],
|
||||
"other": { "stuff": "hello" },
|
||||
"string": "Thing"
|
||||
})
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let ser = to_canonical_json_string(&json).unwrap();
|
||||
let back = from_json_str::<CanonicalJsonValue>(&ser).unwrap();
|
||||
|
||||
assert_eq!(json, back);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_canonical_sorts_keys() {
|
||||
let json: CanonicalJsonValue = json!({
|
||||
"auth": {
|
||||
"success": true,
|
||||
"mxid": "@john.doe:example.com",
|
||||
"profile": {
|
||||
"display_name": "John Doe",
|
||||
"three_pids": [
|
||||
{
|
||||
"medium": "email",
|
||||
"address": "john.doe@example.org"
|
||||
},
|
||||
{
|
||||
"medium": "msisdn",
|
||||
"address": "123456789"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to_json_string(&json).unwrap(),
|
||||
r#"{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}"#
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -6,30 +6,9 @@ use std::{
|
||||
|
||||
use js_int::Int;
|
||||
use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
|
||||
use serde_json::{to_string as to_json_string, Error as JsonError, Value as JsonValue};
|
||||
use serde_json::{to_string as to_json_string, Value as JsonValue};
|
||||
|
||||
/// The set of possible errors when serializing to canonical JSON.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The numeric value failed conversion to js_int::Int.
|
||||
IntConvert,
|
||||
/// The `CanonicalJsonValue` being serialized was larger than 65,535 bytes.
|
||||
JsonSize,
|
||||
/// An error occurred while serializing/deserializing.
|
||||
SerDe(JsonError),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
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::JsonSize => f.write_str("JSON is larger than 65,535 byte max"),
|
||||
Error::SerDe(err) => write!(f, "serde Error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
use super::Error;
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub enum CanonicalJsonValue {
|
||||
@ -96,23 +75,6 @@ pub enum CanonicalJsonValue {
|
||||
Object(BTreeMap<String, CanonicalJsonValue>),
|
||||
}
|
||||
|
||||
impl CanonicalJsonValue {
|
||||
/// Returns a canonical JSON string according to Matrix specification.
|
||||
///
|
||||
/// The method should be preferred over `serde_json::to_string` since it
|
||||
/// checks the size of the canonical string. Matrix canonical JSON enforces
|
||||
/// a size limit of less than 65,535 when sending PDU's for the server-server protocol.
|
||||
pub fn to_canonical_string(&self) -> Result<String, Error> {
|
||||
Ok(to_json_string(self).map_err(Error::SerDe).and_then(|s| {
|
||||
if s.as_bytes().len() > 65_535 {
|
||||
Err(Error::JsonSize)
|
||||
} else {
|
||||
Ok(s)
|
||||
}
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for CanonicalJsonValue {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
@ -211,57 +173,3 @@ impl<'de> Deserialize<'de> for CanonicalJsonValue {
|
||||
Ok(val.try_into().map_err(serde::de::Error::custom)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::convert::TryInto;
|
||||
|
||||
use super::CanonicalJsonValue;
|
||||
use serde_json::{from_str as from_json_str, json, to_string as to_json_string};
|
||||
|
||||
#[test]
|
||||
fn serialize_canon() {
|
||||
let json: CanonicalJsonValue = json!({
|
||||
"a": [1, 2, 3],
|
||||
"other": { "stuff": "hello" },
|
||||
"string": "Thing"
|
||||
})
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
let ser = json.to_canonical_string().unwrap();
|
||||
let back = from_json_str::<CanonicalJsonValue>(&ser).unwrap();
|
||||
|
||||
assert_eq!(json, back);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_canonical_sorts_keys() {
|
||||
let json: CanonicalJsonValue = json!({
|
||||
"auth": {
|
||||
"success": true,
|
||||
"mxid": "@john.doe:example.com",
|
||||
"profile": {
|
||||
"display_name": "John Doe",
|
||||
"three_pids": [
|
||||
{
|
||||
"medium": "email",
|
||||
"address": "john.doe@example.org"
|
||||
},
|
||||
{
|
||||
"medium": "msisdn",
|
||||
"address": "123456789"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
.try_into()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
to_json_string(&json).unwrap(),
|
||||
r#"{"auth":{"mxid":"@john.doe:example.com","profile":{"display_name":"John Doe","three_pids":[{"address":"john.doe@example.org","medium":"email"},{"address":"123456789","medium":"msisdn"}]},"success":true}}"#
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ pub mod time;
|
||||
pub mod urlencoded;
|
||||
|
||||
pub use can_be_empty::{is_empty, CanBeEmpty};
|
||||
pub use canonical_json::value::{CanonicalJsonValue, Error as CanonicalError};
|
||||
pub use canonical_json::{
|
||||
to_string as to_canonical_json_string, value::CanonicalJsonValue, Error as CanonicalJsonError,
|
||||
};
|
||||
pub use empty::vec_as_map_of_empty;
|
||||
|
||||
/// Check whether a value is equal to its default value.
|
||||
|
Loading…
x
Reference in New Issue
Block a user