nil_zonefile/
dns.rs

1use serde::{Deserialize, Serialize, Deserializer};
2use serde::ser::Serializer;
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct Dns {
6    pub zone: Option<String>
7}
8
9// Function to determine if a Dns should be skipped during serialization
10pub fn is_dns_none(dns: &Option<Dns>) -> bool {
11    match dns {
12        None => true,
13        Some(dns) => dns.zone.is_none(),
14    }
15}
16
17// Implement custom serialization
18impl Serialize for Dns {
19    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
20    where
21        S: Serializer,
22    {
23        match &self.zone {
24            Some(zone) => serializer.serialize_str(zone),
25            None => serializer.serialize_none()
26        }
27    }
28}
29
30// Implement custom deserialization
31impl<'de> Deserialize<'de> for Dns {
32    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
33    where
34        D: Deserializer<'de>,
35    {
36        // First try to deserialize as a string
37        let value = serde::de::DeserializeSeed::deserialize(
38            StringOrStruct::default(),
39            deserializer
40        )?;
41        Ok(value)
42    }
43}
44
45#[derive(Default)]
46struct StringOrStruct {
47    _private: ()
48}
49
50impl<'de> serde::de::DeserializeSeed<'de> for StringOrStruct {
51    type Value = Dns;
52
53    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
54    where
55        D: Deserializer<'de>,
56    {
57        // Try as string first
58        struct StringVisitor;
59
60        impl<'de> serde::de::Visitor<'de> for StringVisitor {
61            type Value = Dns;
62
63            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
64                formatter.write_str("string or dns object")
65            }
66
67            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
68            where
69                E: serde::de::Error,
70            {
71                Ok(Dns { zone: Some(value.to_string()) })
72            }
73
74            fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
75            where
76                E: serde::de::Error,
77            {
78                Ok(Dns { zone: Some(value) })
79            }
80
81            fn visit_none<E>(self) -> Result<Self::Value, E>
82            where
83                E: serde::de::Error,
84            {
85                Ok(Dns { zone: None })
86            }
87
88            fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
89            where
90                D: Deserializer<'de>,
91            {
92                Deserialize::deserialize(deserializer)
93            }
94
95            fn visit_unit<E>(self) -> Result<Self::Value, E>
96            where
97                E: serde::de::Error,
98            {
99                Ok(Dns { zone: None })
100            }
101
102            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
103            where
104                A: serde::de::MapAccess<'de>,
105            {
106                let mut zone = None;
107                while let Some(key) = map.next_key::<String>()? {
108                    if key == "zone" {
109                        zone = map.next_value()?;
110                    } else {
111                        map.next_value::<serde::de::IgnoredAny>()?;
112                    }
113                }
114                Ok(Dns { zone })
115            }
116        }
117
118        deserializer.deserialize_any(StringVisitor)
119    }
120}
121
122impl Default for Dns {
123    fn default() -> Self {
124        Self { zone: None }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use serde_json;
132
133    #[test]
134    fn test_dns_serialization() {
135        // Test with Some zone
136        let dns = Dns {
137            zone: Some("example.com".to_string()),
138        };
139        let json = serde_json::to_string(&dns).unwrap();
140        assert_eq!(json, r#""example.com""#);
141
142        // Test with None zone - should serialize as null
143        let dns = Dns { zone: None };
144        let json = serde_json::to_string(&dns).unwrap();
145        assert_eq!(json, "null");
146
147        // Test default - should serialize as null
148        let dns = Dns::default();
149        let json = serde_json::to_string(&dns).unwrap();
150        assert_eq!(json, "null");
151    }
152
153    #[test]
154    fn test_dns_in_struct() {
155        // Test how Dns behaves when it's an optional field in another struct
156        #[derive(Serialize)]
157        struct Container {
158            #[serde(skip_serializing_if = "is_dns_none")]
159            dns: Option<Dns>,
160            other: String,
161        }
162
163        // Test with Some zone
164        let container = Container {
165            dns: Some(Dns {
166                zone: Some("example.com".to_string()),
167            }),
168            other: "test".to_string(),
169        };
170        let json = serde_json::to_string(&container).unwrap();
171        assert_eq!(json, r#"{"dns":"example.com","other":"test"}"#);
172
173        // Test with None zone - should be omitted entirely
174        let container = Container {
175            dns: Some(Dns { zone: None }),
176            other: "test".to_string(),
177        };
178        let json = serde_json::to_string(&container).unwrap();
179        assert_eq!(json, r#"{"other":"test"}"#);
180
181        // Test with None dns
182        let container = Container {
183            dns: None,
184            other: "test".to_string(),
185        };
186        let json = serde_json::to_string(&container).unwrap();
187        assert_eq!(json, r#"{"other":"test"}"#);
188    }
189
190    #[test]
191    fn test_dns_deserialization() {
192        // Test deserializing from string
193        let dns: Dns = serde_json::from_str(r#""example.com""#).unwrap();
194        assert_eq!(dns.zone, Some("example.com".to_string()));
195
196        // Test deserializing from null
197        let dns: Dns = serde_json::from_str("null").unwrap();
198        assert_eq!(dns.zone, None);
199
200        // Test deserializing from empty object
201        let dns: Dns = serde_json::from_str("{}").unwrap();
202        assert_eq!(dns.zone, None);
203
204        // Test deserializing from object with null zone
205        let dns: Dns = serde_json::from_str(r#"{"zone":null}"#).unwrap();
206        assert_eq!(dns.zone, None);
207
208        // Test deserializing from object with zone
209        let dns: Dns = serde_json::from_str(r#"{"zone":"example.com"}"#).unwrap();
210        assert_eq!(dns.zone, Some("example.com".to_string()));
211    }
212}