ruma_common/canonical_json/
value.rs1use std::{collections::BTreeMap, fmt};
2
3use as_variant::as_variant;
4use js_int::{Int, UInt};
5use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
6use serde_json::{Value as JsonValue, to_string as to_json_string};
7
8use super::CanonicalJsonError;
9use crate::serde::{JsonCastable, JsonObject};
10
11pub type CanonicalJsonObject = BTreeMap<String, CanonicalJsonValue>;
13
14impl<T> JsonCastable<CanonicalJsonObject> for T where T: JsonCastable<JsonObject> {}
15
16#[derive(Clone, Default, Eq, PartialEq)]
18#[allow(clippy::exhaustive_enums)]
19pub enum CanonicalJsonValue {
20 #[default]
28 Null,
29
30 Bool(bool),
38
39 Integer(Int),
47
48 String(String),
56
57 Array(Vec<CanonicalJsonValue>),
65
66 Object(CanonicalJsonObject),
76}
77
78impl CanonicalJsonValue {
79 pub fn as_bool(&self) -> Option<bool> {
81 as_variant!(self, Self::Bool).copied()
82 }
83
84 pub fn as_integer(&self) -> Option<Int> {
86 as_variant!(self, Self::Integer).copied()
87 }
88
89 pub fn as_str(&self) -> Option<&str> {
91 as_variant!(self, Self::String)
92 }
93
94 pub fn as_array(&self) -> Option<&[CanonicalJsonValue]> {
96 as_variant!(self, Self::Array)
97 }
98
99 pub fn as_object(&self) -> Option<&CanonicalJsonObject> {
101 as_variant!(self, Self::Object)
102 }
103
104 pub fn as_array_mut(&mut self) -> Option<&mut Vec<CanonicalJsonValue>> {
106 as_variant!(self, Self::Array)
107 }
108
109 pub fn as_object_mut(&mut self) -> Option<&mut CanonicalJsonObject> {
111 as_variant!(self, Self::Object)
112 }
113
114 pub fn is_bool(&self) -> bool {
116 matches!(self, Self::Bool(_))
117 }
118
119 pub fn is_integer(&self) -> bool {
121 matches!(self, Self::Integer(_))
122 }
123
124 pub fn is_string(&self) -> bool {
126 matches!(self, Self::String(_))
127 }
128
129 pub fn is_array(&self) -> bool {
131 matches!(self, Self::Array(_))
132 }
133
134 pub fn is_object(&self) -> bool {
136 matches!(self, Self::Object(_))
137 }
138}
139
140impl fmt::Debug for CanonicalJsonValue {
141 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
142 match *self {
143 Self::Null => formatter.debug_tuple("Null").finish(),
144 Self::Bool(v) => formatter.debug_tuple("Bool").field(&v).finish(),
145 Self::Integer(ref v) => fmt::Debug::fmt(v, formatter),
146 Self::String(ref v) => formatter.debug_tuple("String").field(v).finish(),
147 Self::Array(ref v) => {
148 formatter.write_str("Array(")?;
149 fmt::Debug::fmt(v, formatter)?;
150 formatter.write_str(")")
151 }
152 Self::Object(ref v) => {
153 formatter.write_str("Object(")?;
154 fmt::Debug::fmt(v, formatter)?;
155 formatter.write_str(")")
156 }
157 }
158 }
159}
160
161impl fmt::Display for CanonicalJsonValue {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 write!(f, "{}", to_json_string(&self).map_err(|_| fmt::Error)?)
172 }
173}
174
175impl TryFrom<JsonValue> for CanonicalJsonValue {
176 type Error = CanonicalJsonError;
177
178 fn try_from(val: JsonValue) -> Result<Self, Self::Error> {
179 Ok(match val {
180 JsonValue::Bool(b) => Self::Bool(b),
181 JsonValue::Number(num) => {
182 if !num.is_i64() && !num.is_u64() && num.is_f64() {
187 return Err(CanonicalJsonError::InvalidType("float".to_owned()));
188 }
189
190 Self::Integer(
191 num.as_i64()
192 .and_then(|num| Int::try_from(num).ok())
193 .ok_or(CanonicalJsonError::IntegerOutOfRange)?,
194 )
195 }
196 JsonValue::Array(vec) => {
197 Self::Array(vec.into_iter().map(TryInto::try_into).collect::<Result<Vec<_>, _>>()?)
198 }
199 JsonValue::String(string) => Self::String(string),
200 JsonValue::Object(obj) => Self::Object(
201 obj.into_iter()
202 .map(|(k, v)| Ok((k, v.try_into()?)))
203 .collect::<Result<CanonicalJsonObject, _>>()?,
204 ),
205 JsonValue::Null => Self::Null,
206 })
207 }
208}
209
210impl From<CanonicalJsonValue> for JsonValue {
211 fn from(val: CanonicalJsonValue) -> Self {
212 match val {
213 CanonicalJsonValue::Bool(b) => Self::Bool(b),
214 CanonicalJsonValue::Integer(int) => Self::Number(i64::from(int).into()),
215 CanonicalJsonValue::String(string) => Self::String(string),
216 CanonicalJsonValue::Array(vec) => {
217 Self::Array(vec.into_iter().map(Into::into).collect())
218 }
219 CanonicalJsonValue::Object(obj) => {
220 Self::Object(obj.into_iter().map(|(k, v)| (k, v.into())).collect())
221 }
222 CanonicalJsonValue::Null => Self::Null,
223 }
224 }
225}
226
227impl<T> JsonCastable<CanonicalJsonValue> for T {}
228
229macro_rules! variant_impls {
230 ($variant:ident($ty:ty)) => {
231 impl From<$ty> for CanonicalJsonValue {
232 fn from(val: $ty) -> Self {
233 Self::$variant(val.into())
234 }
235 }
236
237 impl PartialEq<$ty> for CanonicalJsonValue {
238 fn eq(&self, other: &$ty) -> bool {
239 match self {
240 Self::$variant(val) => val == other,
241 _ => false,
242 }
243 }
244 }
245
246 impl PartialEq<CanonicalJsonValue> for $ty {
247 fn eq(&self, other: &CanonicalJsonValue) -> bool {
248 match other {
249 CanonicalJsonValue::$variant(val) => self == val,
250 _ => false,
251 }
252 }
253 }
254 };
255}
256
257variant_impls!(Bool(bool));
258variant_impls!(Integer(Int));
259variant_impls!(String(String));
260variant_impls!(String(&str));
261variant_impls!(Array(Vec<CanonicalJsonValue>));
262variant_impls!(Object(CanonicalJsonObject));
263
264impl From<UInt> for CanonicalJsonValue {
265 fn from(value: UInt) -> Self {
266 Self::Integer(value.into())
267 }
268}
269
270impl Serialize for CanonicalJsonValue {
271 #[inline]
272 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
273 where
274 S: Serializer,
275 {
276 match self {
277 Self::Null => serializer.serialize_unit(),
278 Self::Bool(b) => serializer.serialize_bool(*b),
279 Self::Integer(n) => n.serialize(serializer),
280 Self::String(s) => serializer.serialize_str(s),
281 Self::Array(v) => v.serialize(serializer),
282 Self::Object(m) => {
283 use serde::ser::SerializeMap;
284 let mut map = serializer.serialize_map(Some(m.len()))?;
285 for (k, v) in m {
286 map.serialize_entry(k, v)?;
287 }
288 map.end()
289 }
290 }
291 }
292}
293
294impl<'de> Deserialize<'de> for CanonicalJsonValue {
295 #[inline]
296 fn deserialize<D>(deserializer: D) -> Result<CanonicalJsonValue, D::Error>
297 where
298 D: Deserializer<'de>,
299 {
300 let val = JsonValue::deserialize(deserializer)?;
301 val.try_into().map_err(serde::de::Error::custom)
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use serde_json::json;
308
309 use super::CanonicalJsonValue;
310
311 #[test]
312 fn to_string() {
313 const CANONICAL_STR: &str = r#"{"city":"London","street":"10 Downing Street"}"#;
314
315 let json: CanonicalJsonValue =
316 json!({ "city": "London", "street": "10 Downing Street" }).try_into().unwrap();
317
318 assert_eq!(format!("{json}"), CANONICAL_STR);
319 assert_eq!(format!("{json:#}"), CANONICAL_STR);
320 }
321}