1use serde::{Deserialize, Deserializer, Serialize, Serializer};
12
13#[derive(Debug, Clone, Default)]
15pub struct Strings(pub Vec<String>);
16
17impl Serialize for Strings {
18 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
19 where
20 S: Serializer,
21 {
22 if self.0.len() == 1 {
23 self.0[0].serialize(serializer)
24 } else {
25 self.0.serialize(serializer)
26 }
27 }
28}
29
30impl<'de> Deserialize<'de> for Strings {
31 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
32 where
33 D: Deserializer<'de>,
34 {
35 #[derive(Deserialize)]
36 #[serde(untagged)]
37 enum StringOrVec {
38 String(String),
39 Vec(Vec<String>),
40 }
41
42 match StringOrVec::deserialize(deserializer)? {
43 StringOrVec::String(s) => Ok(Strings(vec![s])),
44 StringOrVec::Vec(v) => Ok(Strings(v)),
45 }
46 }
47}
48
49impl Strings {
50 pub fn is_empty(&self) -> bool {
51 self.0.is_empty()
52 }
53
54 pub fn first(&self) -> Option<&String> {
55 self.0.first()
56 }
57
58 pub fn iter(&self) -> impl Iterator<Item = &String> {
59 self.0.iter()
60 }
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
65pub enum Flag {
66 False,
67 #[default]
68 Default,
69 True,
70}
71
72impl Flag {
73 pub fn with_default(self, default_value: bool) -> bool {
75 match self {
76 Flag::False => false,
77 Flag::Default => default_value,
78 Flag::True => true,
79 }
80 }
81}
82
83impl Serialize for Flag {
84 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85 where
86 S: Serializer,
87 {
88 match self {
89 Flag::False => serializer.serialize_bool(false),
90 Flag::Default => serializer.serialize_none(),
91 Flag::True => serializer.serialize_bool(true),
92 }
93 }
94}
95
96impl<'de> Deserialize<'de> for Flag {
97 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98 where
99 D: Deserializer<'de>,
100 {
101 let opt: Option<bool> = Option::deserialize(deserializer)?;
102 Ok(match opt {
103 Some(true) => Flag::True,
104 Some(false) => Flag::False,
105 None => Flag::Default,
106 })
107 }
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
112pub enum Priority {
113 #[default]
114 Default,
115 Disabled,
116 Value(i64),
117}
118
119impl Priority {
120 pub fn with_default(self, default_value: i64) -> Option<i64> {
121 match self {
122 Priority::Default => Some(default_value),
123 Priority::Disabled => None,
124 Priority::Value(v) => Some(v),
125 }
126 }
127}
128
129impl Serialize for Priority {
130 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
131 where
132 S: Serializer,
133 {
134 match self {
135 Priority::Default => serializer.serialize_none(),
136 Priority::Disabled => serializer.serialize_bool(false),
137 Priority::Value(v) => serializer.serialize_i64(*v),
138 }
139 }
140}
141
142impl<'de> Deserialize<'de> for Priority {
143 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144 where
145 D: Deserializer<'de>,
146 {
147 #[derive(Deserialize)]
148 #[serde(untagged)]
149 enum PriorityValue {
150 Bool(bool),
151 Int(i64),
152 }
153
154 let opt: Option<PriorityValue> = Option::deserialize(deserializer)?;
155 Ok(match opt {
156 None => Priority::Default,
157 Some(PriorityValue::Bool(false)) => Priority::Disabled,
158 Some(PriorityValue::Bool(true)) => Priority::Value(1),
159 Some(PriorityValue::Int(v)) => {
160 if v <= 0 {
161 Priority::Disabled
162 } else {
163 Priority::Value(v)
164 }
165 }
166 })
167 }
168}
169
170#[derive(Debug, Clone, Default, Serialize, Deserialize)]
172pub struct OptionalDuration(
173 #[serde(default, skip_serializing_if = "Option::is_none")] pub Option<String>,
174);
175
176impl OptionalDuration {
177 pub fn is_none(&self) -> bool {
178 self.0.is_none()
179 }
180
181 pub fn as_str(&self) -> Option<&str> {
182 self.0.as_deref()
183 }
184}
185
186#[derive(Debug, Clone, Default, Serialize, Deserialize)]
188pub struct OptionalInteger(
189 #[serde(default, skip_serializing_if = "Option::is_none")] pub Option<i64>,
190);
191
192impl OptionalInteger {
193 pub fn is_none(&self) -> bool {
194 self.0.is_none()
195 }
196
197 pub fn value(&self) -> Option<i64> {
198 self.0
199 }
200
201 pub fn with_default(&self, default: i64) -> i64 {
202 self.0.unwrap_or(default)
203 }
204}
205
206#[derive(Debug, Clone, Default, Serialize, Deserialize)]
208pub struct OptionalString(
209 #[serde(default, skip_serializing_if = "Option::is_none")] pub Option<String>,
210);
211
212impl OptionalString {
213 pub fn is_none(&self) -> bool {
214 self.0.is_none()
215 }
216
217 pub fn as_str(&self) -> Option<&str> {
218 self.0.as_deref()
219 }
220
221 pub fn with_default<'a>(&'a self, default: &'a str) -> &'a str {
222 self.0.as_deref().unwrap_or(default)
223 }
224}
225
226#[derive(Debug, Clone, Default, Serialize, Deserialize)]
228pub struct OptionalBytes(
229 #[serde(default, skip_serializing_if = "Option::is_none")] pub Option<String>,
230);
231
232impl OptionalBytes {
233 pub fn is_none(&self) -> bool {
234 self.0.is_none()
235 }
236
237 pub fn as_str(&self) -> Option<&str> {
238 self.0.as_deref()
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn test_strings_single() {
248 let s: Strings = serde_json::from_str(r#""/ip4/0.0.0.0/tcp/4001""#).unwrap();
249 assert_eq!(s.0.len(), 1);
250 assert_eq!(s.0[0], "/ip4/0.0.0.0/tcp/4001");
251 }
252
253 #[test]
254 fn test_strings_array() {
255 let s: Strings =
256 serde_json::from_str(r#"["/ip4/0.0.0.0/tcp/4001", "/ip6/::/tcp/4001"]"#).unwrap();
257 assert_eq!(s.0.len(), 2);
258 }
259
260 #[test]
261 fn test_flag() {
262 let f: Flag = serde_json::from_str("true").unwrap();
263 assert_eq!(f, Flag::True);
264
265 let f: Flag = serde_json::from_str("false").unwrap();
266 assert_eq!(f, Flag::False);
267
268 let f: Flag = serde_json::from_str("null").unwrap();
269 assert_eq!(f, Flag::Default);
270 }
271
272 #[test]
273 fn test_priority() {
274 let p: Priority = serde_json::from_str("100").unwrap();
275 assert_eq!(p, Priority::Value(100));
276
277 let p: Priority = serde_json::from_str("false").unwrap();
278 assert_eq!(p, Priority::Disabled);
279
280 let p: Priority = serde_json::from_str("null").unwrap();
281 assert_eq!(p, Priority::Default);
282 }
283}