serde_aux/container_attributes.rs
1use serde::de::{DeserializeOwned, Error};
2use serde::{Deserialize, Deserializer};
3
4/// Deserializes a struct without checking for the fields case sensititivity.
5///
6/// # **Notes**
7///
8/// - The following deserializer is incompatible with serde's one. If you wish
9/// to use `serde(rename)`, there is a high risk it won't work. Please see
10/// <https://github.com/vityafx/serde-aux/issues/8> for further information.
11///
12/// # Example:
13///
14/// ```rust
15/// use serde_aux::prelude::*;
16///
17/// #[derive(serde::Deserialize, Debug)]
18/// struct AnotherStruct {
19/// aaa: String,
20/// }
21/// #[derive(serde::Deserialize, Debug)]
22/// struct MyStruct {
23/// #[serde(deserialize_with = "deserialize_struct_case_insensitive")]
24/// another_struct: AnotherStruct,
25/// }
26///
27/// let s = r#"{ "another_struct": { "AaA": "Test example" } }"#;
28/// let a: MyStruct = serde_json::from_str(s).unwrap();
29/// assert_eq!(a.another_struct.aaa, "Test example");
30/// ```
31pub fn deserialize_struct_case_insensitive<'de, T, D>(deserializer: D) -> Result<T, D::Error>
32where
33 T: DeserializeOwned,
34 D: Deserializer<'de>,
35{
36 use serde_json::Value;
37
38 use std::collections::BTreeMap as Map;
39
40 let map = Map::<String, Value>::deserialize(deserializer)?;
41 let lower = map
42 .into_iter()
43 .map(|(k, v)| (k.to_lowercase(), v))
44 .collect();
45 T::deserialize(Value::Object(lower)).map_err(Error::custom)
46}
47
48/// This contains both serialization and ser/deserialization of a enum into and from numbers.
49/// The [reference implementation](https://serde.rs/enum-number.html) does not work if your
50/// enum has negative values. This `enum_number` handles this also.
51///
52/// # Example
53///
54/// ```rust
55/// serde_aux::enum_number_declare!(pub TestEnum {
56/// Up = 1,
57/// None = 0,
58/// Down = -1,
59/// });
60///
61/// let s = r#"1"#;
62/// let a: TestEnum = serde_json::from_str(s).unwrap();
63/// assert_eq!(a, TestEnum::Up);
64///
65/// let s = r#"0"#;
66/// let a: TestEnum = serde_json::from_str(s).unwrap();
67/// assert_eq!(a, TestEnum::None);
68///
69/// let s = r#"-1"#;
70/// let a: TestEnum = serde_json::from_str(s).unwrap();
71/// assert_eq!(a, TestEnum::Down);
72///
73/// let s = r#"5"#;
74/// assert!(serde_json::from_str::<TestEnum>(s).is_err());
75/// ```
76#[macro_export]
77macro_rules! enum_number_declare {
78 ($visibility:vis $name:ident { $($variant:ident = $value:expr, )* }) => {
79 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
80 $visibility enum $name {
81 $($variant = $value,)*
82 }
83
84 impl<'de> serde::Deserialize<'de> for $name {
85 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
86 where D: serde::Deserializer<'de>
87 {
88 use std::fmt;
89 struct Visitor;
90
91 impl<'de> serde::de::Visitor<'de> for Visitor {
92 type Value = $name;
93
94 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
95 formatter.write_str("integer")
96 }
97
98 fn visit_i64<E>(self, value: i64) -> Result<$name, E>
99 where E: serde::de::Error
100 {
101 // Rust does not come with a simple way of converting a
102 // number to an enum, so use a big `match`.
103 match value {
104 $( $value => Ok($name::$variant), )*
105 _ => Err(E::custom(
106 format!("unknown {} value: {}",
107 stringify!($name), value))),
108 }
109 }
110
111 fn visit_u64<E>(self, value: u64) -> Result<$name, E>
112 where E: serde::de::Error
113 {
114 self.visit_i64(value as i64)
115 }
116 }
117
118 // Deserialize the enum from a i64.
119 deserializer.deserialize_i64(Visitor)
120 }
121 }
122 }
123}