1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
91use std::num::{
92 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
93 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
94};
95use std::path::PathBuf;
96
97use crate::config_value_decoder::ConfigValueDecoder;
98use crate::secret::Secret;
99
100impl ConfigValueDecoder for String {
101 fn decode(raw: String) -> Result<String, String> {
102 Ok(raw)
103 }
104}
105
106macro_rules! make_config_value_decoder {
112 ($ty: tt) => {
113 impl ConfigValueDecoder for $ty {
114 fn decode(raw: String) -> Result<$ty, String> {
115 raw.parse::<$ty>().map_err(|e| e.to_string())
116 }
117 }
118 };
119}
120
121macro_rules! make_nested_config_value_decoder {
127 ($ty: tt, $constr: expr) => {
128 impl<T: ConfigValueDecoder> ConfigValueDecoder for $ty<T> {
129 fn decode(raw: String) -> Result<$ty<T>, String> {
130 T::decode(raw).map($constr)
131 }
132 }
133 };
134}
135
136make_nested_config_value_decoder!(Secret, Secret);
138make_nested_config_value_decoder!(Option, Some);
139
140make_config_value_decoder!(bool);
142make_config_value_decoder!(char);
143
144make_config_value_decoder!(u8);
146make_config_value_decoder!(u16);
147make_config_value_decoder!(u32);
148make_config_value_decoder!(u64);
149make_config_value_decoder!(u128);
150make_config_value_decoder!(usize);
151
152make_config_value_decoder!(i8);
154make_config_value_decoder!(i16);
155make_config_value_decoder!(i32);
156make_config_value_decoder!(i64);
157make_config_value_decoder!(i128);
158make_config_value_decoder!(isize);
159
160make_config_value_decoder!(f32);
162make_config_value_decoder!(f64);
163
164make_config_value_decoder!(NonZeroU8);
166make_config_value_decoder!(NonZeroU16);
167make_config_value_decoder!(NonZeroU32);
168make_config_value_decoder!(NonZeroU64);
169make_config_value_decoder!(NonZeroU128);
170make_config_value_decoder!(NonZeroUsize);
171
172make_config_value_decoder!(NonZeroI8);
174make_config_value_decoder!(NonZeroI16);
175make_config_value_decoder!(NonZeroI32);
176make_config_value_decoder!(NonZeroI64);
177make_config_value_decoder!(NonZeroI128);
178make_config_value_decoder!(NonZeroIsize);
179
180make_config_value_decoder!(IpAddr);
182make_config_value_decoder!(Ipv4Addr);
183make_config_value_decoder!(Ipv6Addr);
184make_config_value_decoder!(SocketAddr);
185make_config_value_decoder!(SocketAddrV4);
186make_config_value_decoder!(SocketAddrV6);
187
188make_config_value_decoder!(PathBuf);
190
191#[cfg(test)]
192mod tests {
193 use crate::*;
194 use std::net::*;
195 use std::num::*;
196
197 #[test]
198 fn test_bool_decoder() {
199 assert!(bool::decode("true".to_string()).unwrap());
200 assert!(!bool::decode("false".to_string()).unwrap());
201 assert!(bool::decode("invalid".to_string()).is_err());
202 }
203
204 #[test]
205 fn test_char_decoder() {
206 assert_eq!(char::decode("a".to_string()).unwrap(), 'a');
207 assert_eq!(char::decode("€".to_string()).unwrap(), '€');
208 assert!(char::decode("ab".to_string()).is_err());
209 assert!(char::decode("".to_string()).is_err());
210 }
211
212 #[test]
213 fn test_unsigned_integer_decoders() {
214 assert_eq!(u8::decode("255".to_string()).unwrap(), 255u8);
216 assert_eq!(u16::decode("65535".to_string()).unwrap(), 65535u16);
217 assert_eq!(
218 u32::decode("4294967295".to_string()).unwrap(),
219 4294967295u32
220 );
221 assert_eq!(
222 u64::decode("18446744073709551615".to_string()).unwrap(),
223 18446744073709551615u64
224 );
225 assert_eq!(
226 u128::decode("340282366920938463463374607431768211455".to_string()).unwrap(),
227 340282366920938463463374607431768211455u128
228 );
229 assert_eq!(usize::decode("1000".to_string()).unwrap(), 1000usize);
230
231 assert!(u8::decode("256".to_string()).is_err());
233 assert!(u16::decode("65536".to_string()).is_err());
234
235 assert!(u32::decode("not_a_number".to_string()).is_err());
237 assert!(u64::decode("-1".to_string()).is_err());
238 }
239
240 #[test]
241 fn test_signed_integer_decoders() {
242 assert_eq!(i8::decode("-128".to_string()).unwrap(), -128i8);
244 assert_eq!(i16::decode("-32768".to_string()).unwrap(), -32768i16);
245 assert_eq!(
246 i32::decode("-2147483648".to_string()).unwrap(),
247 -2147483648i32
248 );
249 assert_eq!(
250 i64::decode("-9223372036854775808".to_string()).unwrap(),
251 -9223372036854775808i64
252 );
253 assert_eq!(
254 i128::decode("-170141183460469231731687303715884105728".to_string()).unwrap(),
255 -170141183460469231731687303715884105728i128
256 );
257 assert_eq!(isize::decode("-1000".to_string()).unwrap(), -1000isize);
258
259 assert_eq!(i8::decode("127".to_string()).unwrap(), 127i8);
261 assert_eq!(i32::decode("42".to_string()).unwrap(), 42i32);
262
263 assert!(i8::decode("128".to_string()).is_err());
265 assert!(i16::decode("32768".to_string()).is_err());
266
267 assert!(i32::decode("not_a_number".to_string()).is_err());
269 }
270
271 #[test]
272 #[allow(clippy::approx_constant)]
273 fn test_float_decoders() {
274 assert_eq!(f32::decode("3.14".to_string()).unwrap(), 3.14f32);
275 assert_eq!(f64::decode("2.71828".to_string()).unwrap(), 2.71828f64);
276 assert_eq!(f32::decode("-1.5".to_string()).unwrap(), -1.5f32);
277 assert_eq!(f64::decode("0.0".to_string()).unwrap(), 0.0f64);
278 assert_eq!(f32::decode("1e10".to_string()).unwrap(), 1e10f32);
279 assert_eq!(f64::decode("1.5e-5".to_string()).unwrap(), 1.5e-5f64);
280
281 assert!(f32::decode("not_a_float".to_string()).is_err());
283 }
284
285 #[test]
286 fn test_nonzero_unsigned_decoders() {
287 assert_eq!(NonZeroU8::decode("1".to_string()).unwrap().get(), 1);
288 assert_eq!(NonZeroU16::decode("100".to_string()).unwrap().get(), 100);
289 assert_eq!(NonZeroU32::decode("1000".to_string()).unwrap().get(), 1000);
290 assert_eq!(
291 NonZeroU64::decode("10000".to_string()).unwrap().get(),
292 10000
293 );
294 assert_eq!(
295 NonZeroU128::decode("100000".to_string()).unwrap().get(),
296 100000
297 );
298 assert_eq!(NonZeroUsize::decode("42".to_string()).unwrap().get(), 42);
299
300 assert!(NonZeroU8::decode("0".to_string()).is_err());
301 assert!(NonZeroU32::decode("0".to_string()).is_err());
302 assert_eq!(
303 NonZeroU16::decode("not_a_number".to_string()).unwrap_err(),
304 "invalid digit found in string"
305 );
306 }
307
308 #[test]
309 fn test_nonzero_signed_decoders() {
310 assert_eq!(NonZeroI8::decode("1".to_string()).unwrap().get(), 1);
311 assert_eq!(NonZeroI16::decode("-100".to_string()).unwrap().get(), -100);
312 assert_eq!(NonZeroI32::decode("1000".to_string()).unwrap().get(), 1000);
313 assert_eq!(
314 NonZeroI64::decode("-10000".to_string()).unwrap().get(),
315 -10000
316 );
317 assert_eq!(
318 NonZeroI128::decode("100000".to_string()).unwrap().get(),
319 100000
320 );
321 assert_eq!(NonZeroIsize::decode("-42".to_string()).unwrap().get(), -42);
322
323 assert!(NonZeroI8::decode("0".to_string()).is_err());
324 assert!(NonZeroI32::decode("0".to_string()).is_err());
325 assert_eq!(
326 NonZeroI16::decode("not_a_number".to_string()).unwrap_err(),
327 "invalid digit found in string"
328 );
329 }
330
331 #[test]
332 fn test_ip_address_decoders() {
333 assert_eq!(
334 IpAddr::decode("192.168.1.1".to_string()).unwrap(),
335 "192.168.1.1".parse::<IpAddr>().unwrap()
336 );
337 assert_eq!(
338 IpAddr::decode("::1".to_string()).unwrap(),
339 "::1".parse::<IpAddr>().unwrap()
340 );
341
342 assert_eq!(
343 Ipv4Addr::decode("127.0.0.1".to_string()).unwrap(),
344 Ipv4Addr::new(127, 0, 0, 1)
345 );
346 assert_eq!(
347 Ipv4Addr::decode("192.168.0.1".to_string()).unwrap(),
348 Ipv4Addr::new(192, 168, 0, 1)
349 );
350
351 assert_eq!(
353 Ipv6Addr::decode("::1".to_string()).unwrap(),
354 Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)
355 );
356 assert_eq!(
357 Ipv6Addr::decode("2001:db8::1".to_string()).unwrap(),
358 "2001:db8::1".parse::<Ipv6Addr>().unwrap()
359 );
360
361 assert_eq!(
363 Ipv4Addr::decode("256.1.1.1".to_string()).unwrap_err(),
364 "invalid IPv4 address syntax"
365 );
366 assert_eq!(
367 Ipv6Addr::decode("not_an_ip".to_string()).unwrap_err(),
368 "invalid IPv6 address syntax"
369 );
370 }
371
372 #[test]
373 fn test_socket_address_decoders() {
374 assert_eq!(
375 SocketAddr::decode("127.0.0.1:8080".to_string()).unwrap(),
376 "127.0.0.1:8080".parse::<SocketAddr>().unwrap()
377 );
378 assert_eq!(
379 SocketAddr::decode("[::1]:8080".to_string()).unwrap(),
380 "[::1]:8080".parse::<SocketAddr>().unwrap()
381 );
382
383 assert_eq!(
385 SocketAddrV4::decode("192.168.1.1:3000".to_string()).unwrap(),
386 "192.168.1.1:3000".parse::<SocketAddrV4>().unwrap()
387 );
388
389 assert_eq!(
391 SocketAddrV6::decode("[2001:db8::1]:8080".to_string()).unwrap(),
392 "[2001:db8::1]:8080".parse::<SocketAddrV6>().unwrap()
393 );
394
395 assert_eq!(
397 SocketAddr::decode("127.0.0.1".to_string()).unwrap_err(),
398 "invalid socket address syntax"
399 );
400 assert_eq!(
401 SocketAddr::decode("not_a_socket".to_string()).unwrap_err(),
402 "invalid socket address syntax"
403 );
404 }
405
406 #[test]
407 fn test_option_decoder() {
408 assert_eq!(
410 Option::<String>::decode("hello".to_string()).unwrap(),
411 Some("hello".to_string())
412 );
413 assert_eq!(Option::<i32>::decode("42".to_string()).unwrap(), Some(42));
414 assert_eq!(
415 Option::<bool>::decode("true".to_string()).unwrap(),
416 Some(true)
417 );
418
419 assert!(Option::<i32>::decode("not_a_number".to_string()).is_err());
420 }
421
422 #[test]
423 fn test_secret_decoder() {
424 let secret = Secret::<String>::decode("my_secret".to_string()).unwrap();
426 assert_eq!(*secret, "my_secret");
427
428 let secret = Secret::<i32>::decode("42".to_string()).unwrap();
429 assert_eq!(*secret, 42);
430
431 assert!(Secret::<i32>::decode("not_a_number".to_string()).is_err());
432 }
433}