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