alloy_serde/
optional.rs

1//! Serde functions for encoding optional values.
2
3use serde::{Deserialize, Deserializer};
4
5/// For use with serde's `deserialize_with` on a sequence that must be
6/// deserialized as a single but optional (i.e. possibly `null`) value.
7pub fn null_as_default<'de, T, D>(deserializer: D) -> Result<T, D::Error>
8where
9    T: Deserialize<'de> + Default,
10    D: Deserializer<'de>,
11{
12    Option::<T>::deserialize(deserializer).map(Option::unwrap_or_default)
13}
14
15/// For use with serde's `deserialize_with` on a field that must be missing.
16pub fn reject_if_some<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
17where
18    T: Deserialize<'de>,
19    D: Deserializer<'de>,
20{
21    let value = Option::<T>::deserialize(deserializer)?;
22
23    if value.is_some() {
24        return Err(serde::de::Error::custom("unexpected value"));
25    }
26
27    Ok(value)
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33    use serde_json::json;
34
35    #[derive(Debug, Deserialize, PartialEq)]
36    struct TestStruct {
37        #[serde(default, deserialize_with = "null_as_default")]
38        value: Vec<i32>,
39
40        #[serde(default, deserialize_with = "reject_if_some")]
41        should_be_none: Option<String>,
42    }
43
44    #[test]
45    fn test_null_as_default_with_null() {
46        let json_data = json!({ "value": null });
47        let result: TestStruct = serde_json::from_value(json_data).unwrap();
48        assert_eq!(result.value, Vec::<i32>::new());
49    }
50
51    #[test]
52    fn test_null_as_default_with_value() {
53        let json_data = json!({ "value": [1, 2, 3] });
54        let result: TestStruct = serde_json::from_value(json_data).unwrap();
55        assert_eq!(result.value, vec![1, 2, 3]);
56    }
57
58    #[test]
59    fn test_null_as_default_with_missing_field() {
60        let json_data = json!({});
61        let result: TestStruct = serde_json::from_value(json_data).unwrap();
62        assert_eq!(result.value, Vec::<i32>::new());
63    }
64
65    #[test]
66    fn test_reject_if_some_with_none() {
67        let json_data = json!({});
68        let result: TestStruct = serde_json::from_value(json_data).unwrap();
69        assert_eq!(result.should_be_none, None);
70    }
71
72    #[test]
73    fn test_reject_if_some_with_some() {
74        let json_data = json!({ "should_be_none": "unexpected value" });
75        let result: Result<TestStruct, _> = serde_json::from_value(json_data);
76        assert!(result.is_err());
77    }
78}