1use std::convert::Infallible;
52use std::fmt;
53use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
54use std::ops::Deref;
55use std::path::PathBuf;
56use std::sync::LazyLock;
57use std::time::Duration;
58
59pub trait ParseEnv: Sized {
64 type Err: fmt::Display;
67 fn parse_env(value: String) -> Result<Self, Self::Err>;
69}
70
71#[derive(Debug, Clone)]
73pub struct ParseError {
74 type_name: &'static str,
75 msg: String,
76}
77
78impl ParseError {
79 pub fn from_msg<T, S: ToString>(msg: S) -> Self {
80 Self {
81 type_name: std::any::type_name::<T>(),
82 msg: msg.to_string(),
83 }
84 }
85
86 fn with_type_name<T>(mut self) -> Self {
87 self.type_name = std::any::type_name::<T>();
88 self
89 }
90}
91
92impl fmt::Display for ParseError {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "failed to parse as {}: {}", self.type_name, &self.msg)
95 }
96}
97
98macro_rules! gen_parse_env_using_fromstr {
100 ($ty: ty) => {
101 impl ParseEnv for $ty {
102 type Err = $crate::ParseError;
103
104 fn parse_env(value: String) -> Result<Self, Self::Err> {
105 value
106 .parse()
107 .map_err(|e| $crate::ParseError::from_msg::<Self, _>(e))
108 }
109 }
110 };
111}
112
113gen_parse_env_using_fromstr!(f32);
114gen_parse_env_using_fromstr!(f64);
115gen_parse_env_using_fromstr!(i8);
116gen_parse_env_using_fromstr!(i16);
117gen_parse_env_using_fromstr!(i32);
118gen_parse_env_using_fromstr!(i64);
119gen_parse_env_using_fromstr!(i128);
120gen_parse_env_using_fromstr!(isize);
121gen_parse_env_using_fromstr!(u8);
122gen_parse_env_using_fromstr!(u16);
123gen_parse_env_using_fromstr!(u32);
124gen_parse_env_using_fromstr!(u64);
125gen_parse_env_using_fromstr!(u128);
126gen_parse_env_using_fromstr!(usize);
127gen_parse_env_using_fromstr!(IpAddr);
128gen_parse_env_using_fromstr!(Ipv4Addr);
129gen_parse_env_using_fromstr!(Ipv6Addr);
130gen_parse_env_using_fromstr!(PathBuf);
131gen_parse_env_using_fromstr!(SocketAddr);
132
133impl ParseEnv for String {
134 type Err = Infallible;
135
136 fn parse_env(value: String) -> Result<Self, Self::Err> {
137 Ok(value)
138 }
139}
140
141impl ParseEnv for &'static str {
142 type Err = Infallible;
143
144 fn parse_env(value: String) -> Result<Self, Self::Err> {
145 Ok(Box::leak(Box::new(value)))
146 }
147}
148
149impl ParseEnv for Duration {
151 type Err = ParseError;
152
153 fn parse_env(value: String) -> Result<Self, Self::Err> {
154 match ParseEnv::parse_env(value) {
155 Ok(secs) => Ok(Duration::from_secs_f64(secs)),
156 Err(e) => Err(e.with_type_name::<Self>()),
157 }
158 }
159}
160
161impl<T> ParseEnv for Vec<T>
163where
164 T: ParseEnv,
165{
166 type Err = <T as ParseEnv>::Err;
167
168 fn parse_env(value: String) -> Result<Self, Self::Err> {
169 value
170 .split(',')
171 .map(|v| ParseEnv::parse_env(v.to_owned()))
172 .collect()
173 }
174}
175
176impl<T> ParseEnv for Option<T>
177where
178 T: ParseEnv,
179{
180 type Err = <T as ParseEnv>::Err;
181
182 fn parse_env(value: String) -> Result<Self, Self::Err> {
183 Ok(Some(ParseEnv::parse_env(value)?))
184 }
185}
186
187impl ParseEnv for bool {
193 type Err = ParseError;
194
195 fn parse_env(mut value: String) -> Result<Self, Self::Err> {
196 value.make_ascii_lowercase();
197 match value.as_str() {
198 "true" | "1" => Ok(true),
199 "false" | "0" => Ok(false),
200 _ => Err(ParseError::from_msg::<Self, _>(
201 "expected either true or false",
202 )),
203 }
204 }
205}
206
207pub struct LazyEnv<T> {
209 inner: LazyLock<T>,
210}
211
212impl<T> LazyEnv<T> {
213 #[inline]
214 #[doc(hidden)]
215 pub const fn new(init_fn: fn() -> T) -> Self {
216 Self {
217 inner: LazyLock::new(init_fn),
218 }
219 }
220}
221
222impl<T> Deref for LazyEnv<T> {
223 type Target = T;
224
225 fn deref(&self) -> &Self::Target {
226 &self.inner
227 }
228}
229
230impl<T> fmt::Debug for LazyEnv<T>
231where
232 T: fmt::Debug,
233{
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 let inner = &*self.inner;
236 inner.fmt(f)
237 }
238}
239
240impl<T> fmt::Display for LazyEnv<T>
241where
242 T: fmt::Display,
243{
244 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 let inner = &*self.inner;
246 inner.fmt(f)
247 }
248}
249
250#[doc(hidden)]
252#[inline]
253pub fn __apply_parse_fn<F, T, E>(func: F, key: &'static str, val: String) -> T
254where
255 F: Fn(String) -> Result<T, E>,
256 E: fmt::Display,
257{
258 match func(val) {
259 Ok(val) => val,
260 Err(e) => __invalid_env_var(key, e),
261 }
262}
263
264#[doc(hidden)]
265pub fn __invalid_env_var(key: &'static str, err: impl fmt::Display) -> ! {
266 panic!("Invalid environment variable {}, {}", key, err)
267}
268
269#[doc(hidden)]
270pub fn __missing_env_var(key: &'static str) -> ! {
271 panic!("Missing required environment variable {}", key)
272}
273
274#[doc(hidden)]
276#[macro_export(local_inner_macros)]
277macro_rules! __env_flag_inner {
278 ($(#[$attr:meta])* ($($vis:tt)*) $key:ident : $ty:ty = $default:expr, $parse_fn:expr; $($rem:tt)*) => {
279 $(#[$attr])*
280 $($vis)* static $key: $crate::LazyEnv<$ty> = $crate::LazyEnv::new(|| {
281 match ::std::env::var(::std::stringify!($key)) {
282 Ok(value) => $crate::__apply_parse_fn($parse_fn, ::std::stringify!($key), value),
283 Err(_) => $default(),
284 }
285 });
286
287 env_flags!($($rem)*);
288 };
289}
290
291#[macro_export(local_inner_macros)]
297macro_rules! env_flags {
298 ($(#[$attr:meta])* $key:ident : $ty:ty; $($rem:tt)*) => {
300 __env_flag_inner!($(#[$attr])* () $key : $ty = || $crate::__missing_env_var(::std::stringify!($key)), $crate::ParseEnv::parse_env; $($rem)*);
301 };
302 ($(#[$attr:meta])* pub $key:ident : $ty:ty; $($rem:tt)*) => {
303 __env_flag_inner!($(#[$attr])* (pub) $key : $ty = || $crate::__missing_env_var(::std::stringify!($key)), $crate::ParseEnv::parse_env; $($rem)*);
304 };
305 ($(#[$attr:meta])* pub ($($vis:tt)+) $key:ident : $ty:ty; $($rem:tt)*) => {
306 __env_flag_inner!($(#[$attr])* (pub ($($vis)+)) $key : $ty = || $crate::__missing_env_var(::std::stringify!($key)), $crate::ParseEnv::parse_env; $($rem)*);
307 };
308
309 ($(#[$attr:meta])* $key:ident : $ty:ty = $default:expr; $($rem:tt)*) => {
311 __env_flag_inner!($(#[$attr])* () $key : $ty = || $default, $crate::ParseEnv::parse_env; $($rem)*);
312 };
313 ($(#[$attr:meta])* pub $key:ident : $ty:ty = $default:expr; $($rem:tt)*) => {
314 __env_flag_inner!($(#[$attr])* (pub) $key : $ty = || $default, $crate::ParseEnv::parse_env; $($rem)*);
315 };
316 ($(#[$attr:meta])* pub ($($vis:tt)+) $key:ident : $ty:ty = $default:expr; $($rem:tt)*) => {
317 __env_flag_inner!($(#[$attr])* (pub ($($vis)+)) $key : $ty = || $default, $crate::ParseEnv::parse_env; $($rem)*);
318 };
319
320 ($(#[$attr:meta])* $key:ident : $ty:ty, $parse_fn:expr; $($rem:tt)*) => {
322 __env_flag_inner!($(#[$attr])* () $key : $ty = || $crate::__missing_env_var(::std::stringify!($key)), $parse_fn; $($rem)*);
323 };
324 ($(#[$attr:meta])* pub $key:ident : $ty:ty, $parse_fn:expr; $($rem:tt)*) => {
325 __env_flag_inner!($(#[$attr])* (pub) $key : $ty = || $crate::__missing_env_var(::std::stringify!($key)), $parse_fn; $($rem)*);
326 };
327 ($(#[$attr:meta])* pub ($($vis:tt)+) $key:ident : $ty:ty, $parse_fn:expr; $($rem:tt)*) => {
328 __env_flag_inner!($(#[$attr])* (pub ($($vis)+)) $key : $ty = || $crate::__missing_env_var(::std::stringify!($key)), $parse_fn; $($rem)*);
329 };
330
331 ($(#[$attr:meta])* $key:ident : $ty:ty = $default:expr, $parse_fn:expr; $($rem:tt)*) => {
333 __env_flag_inner!($(#[$attr])* () $key : $ty = || $default, $parse_fn; $($rem)*);
334 };
335 ($(#[$attr:meta])* pub $key:ident : $ty:ty = $default:expr, $parse_fn:expr; $($rem:tt)*) => {
336 __env_flag_inner!($(#[$attr])* (pub) $key : $ty = || $default, $parse_fn; $($rem)*);
337 };
338 ($(#[$attr:meta])* pub ($($vis:tt)+) $key:ident : $ty:ty = $default:expr, $parse_fn:expr; $($rem:tt)*) => {
339 __env_flag_inner!($(#[$attr])* (pub ($($vis)+)) $key : $ty = || $default, $parse_fn; $($rem)*);
340 };
341
342 () => {};
343}
344
345#[cfg(test)]
346mod test {
347 use super::*;
348
349 #[test]
350 fn test_key_type_set() {
351 std::env::set_var("ENV_FLAGS_TEST_KEY_TYPE_SET_PRIV", "80");
352 std::env::set_var("ENV_FLAGS_TEST_KEY_TYPE_SET_CRATE", "81");
353 std::env::set_var("ENV_FLAGS_TEST_KEY_TYPE_SET_PUB", "82");
354 env_flags! {
355 ENV_FLAGS_TEST_KEY_TYPE_SET_PRIV: u16;
356 pub(crate) ENV_FLAGS_TEST_KEY_TYPE_SET_CRATE: u16;
357 pub ENV_FLAGS_TEST_KEY_TYPE_SET_PUB: u16;
358 };
359 assert_eq!(*ENV_FLAGS_TEST_KEY_TYPE_SET_PRIV, 80u16);
360 assert_eq!(*ENV_FLAGS_TEST_KEY_TYPE_SET_CRATE, 81u16);
361 assert_eq!(*ENV_FLAGS_TEST_KEY_TYPE_SET_PUB, 82u16);
362 }
363
364 #[test]
365 #[should_panic]
366 fn test_key_type_unset() {
367 env_flags! {
368 pub ENV_FLAGS_TEST_KEY_TYPE_UNSET: u16;
369 };
370 let _ = *ENV_FLAGS_TEST_KEY_TYPE_UNSET;
371 }
372
373 #[test]
374 fn test_default() {
375 std::env::set_var("ENV_FLAGS_TEST_DEFAULT_SET_PRIV", "goodbye");
376 std::env::set_var("ENV_FLAGS_TEST_DEFAULT_SET_CRATE", "goodbye");
377 std::env::set_var("ENV_FLAGS_TEST_DEFAULT_SET_PUB", "goodbye");
378 env_flags! {
379 ENV_FLAGS_TEST_DEFAULT_SET_PRIV: &str = "hello";
380 pub(crate) ENV_FLAGS_TEST_DEFAULT_SET_CRATE: &str = "hello";
381 pub ENV_FLAGS_TEST_DEFAULT_SET_PUB: &str = "hello";
382
383 pub ENV_FLAGS_TEST_DEFAULT_UNSET: &str = "world";
384 };
385 assert_eq!(*ENV_FLAGS_TEST_DEFAULT_SET_PRIV, "goodbye");
386 assert_eq!(*ENV_FLAGS_TEST_DEFAULT_SET_CRATE, "goodbye");
387 assert_eq!(*ENV_FLAGS_TEST_DEFAULT_SET_PUB, "goodbye");
388
389 assert_eq!(*ENV_FLAGS_TEST_DEFAULT_UNSET, "world");
390 }
391
392 #[test]
393 fn test_parse_fn() {
394 std::env::set_var("ENV_FLAGS_TEST_PARSE_FN_PRIV", "250");
395 std::env::set_var("ENV_FLAGS_TEST_PARSE_FN_CRATE", "5");
396 std::env::set_var("ENV_FLAGS_TEST_PARSE_FN_PUB", "120");
397 env_flags! {
398 ENV_FLAGS_TEST_PARSE_FN_PRIV: Duration, |val| val.parse().map(Duration::from_millis);
399 pub(crate) ENV_FLAGS_TEST_PARSE_FN_CRATE: Duration, |val| val.parse().map(Duration::from_secs);
400 pub ENV_FLAGS_TEST_PARSE_FN_PUB: Duration, |val| val.parse().map(Duration::from_nanos);
401 };
402 assert_eq!(*ENV_FLAGS_TEST_PARSE_FN_PRIV, Duration::from_millis(250));
403 assert_eq!(*ENV_FLAGS_TEST_PARSE_FN_CRATE, Duration::from_secs(5));
404 assert_eq!(*ENV_FLAGS_TEST_PARSE_FN_PUB, Duration::from_nanos(120));
405 }
406
407 #[test]
408 #[should_panic]
409 fn test_parse_fn_unset() {
410 env_flags! {
411 pub(crate) ENV_FLAGS_TEST_PARSE_FN_UNSET: Duration, |val| val.parse().map(Duration::from_millis);
412 };
413 let _ = *ENV_FLAGS_TEST_PARSE_FN_UNSET;
414 }
415
416 #[test]
417 fn test_parse_fn_default() {
418 std::env::set_var("ENV_FLAGS_TEST_PARSE_FN_DEFAULT_PRIV", "10");
419 std::env::set_var("ENV_FLAGS_TEST_PARSE_FN_DEFAULT_CRATE", "11");
420 std::env::set_var("ENV_FLAGS_TEST_PARSE_FN_DEFAULT_PUB", "12");
421 env_flags! {
422 ENV_FLAGS_TEST_PARSE_FN_DEFAULT_PRIV: Duration = Duration::from_millis(5), |val| val.parse().map(Duration::from_millis);
423 pub(crate) ENV_FLAGS_TEST_PARSE_FN_DEFAULT_CRATE: Duration = Duration::from_millis(5), |val| val.parse().map(Duration::from_millis);
424 pub ENV_FLAGS_TEST_PARSE_FN_DEFAULT_PUB: Duration = Duration::from_millis(5), |val| val.parse().map(Duration::from_millis);
425
426 ENV_FLAGS_TEST_PARSE_FN_DEFAULT_UNSET: Duration = Duration::from_millis(5), |val| val.parse().map(Duration::from_millis);
427 };
428 assert_eq!(
429 *ENV_FLAGS_TEST_PARSE_FN_DEFAULT_PRIV,
430 Duration::from_millis(10)
431 );
432 assert_eq!(
433 *ENV_FLAGS_TEST_PARSE_FN_DEFAULT_CRATE,
434 Duration::from_millis(11)
435 );
436 assert_eq!(
437 *ENV_FLAGS_TEST_PARSE_FN_DEFAULT_PUB,
438 Duration::from_millis(12)
439 );
440 assert_eq!(
441 *ENV_FLAGS_TEST_PARSE_FN_DEFAULT_UNSET,
442 Duration::from_millis(5)
443 );
444 }
445
446 #[test]
447 fn test_types_f32() {
448 std::env::set_var("ENV_FLAGS_TEST_TYPES_F32_POS", "1.2");
449 std::env::set_var("ENV_FLAGS_TEST_TYPES_F32_NEG", "-3.2");
450 std::env::set_var("ENV_FLAGS_TEST_TYPES_F32_NAN", "nan");
451 std::env::set_var("ENV_FLAGS_TEST_TYPES_F32_INF", "inf");
452 env_flags! {
453 ENV_FLAGS_TEST_TYPES_F32_POS: f32;
454 ENV_FLAGS_TEST_TYPES_F32_NEG: f32;
455 ENV_FLAGS_TEST_TYPES_F32_NAN: f32;
456 ENV_FLAGS_TEST_TYPES_F32_INF: f32;
457 };
458 assert_eq!(*ENV_FLAGS_TEST_TYPES_F32_POS, 1.2);
459 assert_eq!(*ENV_FLAGS_TEST_TYPES_F32_NEG, -3.2);
460 assert!(ENV_FLAGS_TEST_TYPES_F32_NAN.is_nan());
461 assert!(ENV_FLAGS_TEST_TYPES_F32_INF.is_infinite());
462 }
463
464 #[test]
465 #[should_panic]
466 fn test_invalid_f32() {
467 std::env::set_var("ENV_FLAGS_TEST_INVALID_F32", "cat");
468 env_flags! {
469 ENV_FLAGS_TEST_INVALID_F32: f32 = 0.0;
470 };
471 let _ = *ENV_FLAGS_TEST_INVALID_F32;
472 }
473
474 #[test]
475 fn test_types_f64() {
476 std::env::set_var("ENV_FLAGS_TEST_TYPES_F64_POS", "41.1");
477 std::env::set_var("ENV_FLAGS_TEST_TYPES_F64_NEG", "-0.4");
478 std::env::set_var("ENV_FLAGS_TEST_TYPES_F64_NAN", "nan");
479 std::env::set_var("ENV_FLAGS_TEST_TYPES_F64_INF", "inf");
480 env_flags! {
481 ENV_FLAGS_TEST_TYPES_F64_POS: f64;
482 ENV_FLAGS_TEST_TYPES_F64_NEG: f64;
483 ENV_FLAGS_TEST_TYPES_F64_NAN: f64;
484 ENV_FLAGS_TEST_TYPES_F64_INF: f64;
485 };
486 assert_eq!(*ENV_FLAGS_TEST_TYPES_F64_POS, 41.1);
487 assert_eq!(*ENV_FLAGS_TEST_TYPES_F64_NEG, -0.4);
488 assert!(ENV_FLAGS_TEST_TYPES_F64_NAN.is_nan());
489 assert!(ENV_FLAGS_TEST_TYPES_F64_INF.is_infinite());
490 }
491
492 #[test]
493 #[should_panic]
494 fn test_invalid_f64() {
495 std::env::set_var("ENV_FLAGS_TEST_INVALID_F64", "cat");
496 env_flags! {
497 ENV_FLAGS_TEST_INVALID_F64: f64 = 0.0;
498 };
499 let _ = *ENV_FLAGS_TEST_INVALID_F64;
500 }
501
502 #[test]
503 fn test_types_i8() {
504 std::env::set_var("ENV_FLAGS_TEST_TYPES_I8_POS", "4");
505 std::env::set_var("ENV_FLAGS_TEST_TYPES_I8_NEG", "-4");
506 env_flags! {
507 ENV_FLAGS_TEST_TYPES_I8_POS: i8;
508 ENV_FLAGS_TEST_TYPES_I8_NEG: i8;
509 };
510 assert_eq!(*ENV_FLAGS_TEST_TYPES_I8_POS, 4);
511 assert_eq!(*ENV_FLAGS_TEST_TYPES_I8_NEG, -4);
512 }
513
514 #[test]
515 #[should_panic]
516 fn test_invalid_i8() {
517 std::env::set_var("ENV_FLAGS_TEST_INVALID_I8", "128");
518 env_flags! {
519 ENV_FLAGS_TEST_INVALID_I8: i8;
520 };
521 let _ = *ENV_FLAGS_TEST_INVALID_I8;
522 }
523
524 #[test]
525 fn test_types_i16() {
526 std::env::set_var("ENV_FLAGS_TEST_TYPES_I16_POS", "2559");
527 std::env::set_var("ENV_FLAGS_TEST_TYPES_I16_NEG", "-2559");
528 env_flags! {
529 ENV_FLAGS_TEST_TYPES_I16_POS: i16;
530 ENV_FLAGS_TEST_TYPES_I16_NEG: i16;
531 };
532 assert_eq!(*ENV_FLAGS_TEST_TYPES_I16_POS, 2559);
533 assert_eq!(*ENV_FLAGS_TEST_TYPES_I16_NEG, -2559);
534 }
535
536 #[test]
537 #[should_panic]
538 fn test_invalid_i16() {
539 std::env::set_var("ENV_FLAGS_TEST_INVALID_I16", "32768");
540 env_flags! {
541 ENV_FLAGS_TEST_INVALID_I16: i16 = 0;
542 };
543 let _ = *ENV_FLAGS_TEST_INVALID_I16;
544 }
545
546 #[test]
547 fn test_types_i32() {
548 std::env::set_var("ENV_FLAGS_TEST_TYPES_I32_POS", "124");
549 std::env::set_var("ENV_FLAGS_TEST_TYPES_I32_NEG", "-124");
550 env_flags! {
551 ENV_FLAGS_TEST_TYPES_I32_POS: i32;
552 ENV_FLAGS_TEST_TYPES_I32_NEG: i32;
553 };
554 assert_eq!(*ENV_FLAGS_TEST_TYPES_I32_POS, 124);
555 assert_eq!(*ENV_FLAGS_TEST_TYPES_I32_NEG, -124);
556 }
557
558 #[test]
559 #[should_panic]
560 fn test_invalid_i32() {
561 std::env::set_var("ENV_FLAGS_TEST_INVALID_I32", "2147483648");
562 env_flags! {
563 ENV_FLAGS_TEST_INVALID_I32: i32 = 0;
564 };
565 let _ = *ENV_FLAGS_TEST_INVALID_I32;
566 }
567
568 #[test]
569 fn test_types_i64() {
570 std::env::set_var("ENV_FLAGS_TEST_TYPES_I64_POS", "13966932211");
571 std::env::set_var("ENV_FLAGS_TEST_TYPES_I64_NEG", "-13966932211");
572 env_flags! {
573 ENV_FLAGS_TEST_TYPES_I64_POS: i64;
574 ENV_FLAGS_TEST_TYPES_I64_NEG: i64;
575 }
576 assert_eq!(*ENV_FLAGS_TEST_TYPES_I64_POS, 13966932211);
577 assert_eq!(*ENV_FLAGS_TEST_TYPES_I64_NEG, -13966932211);
578 }
579
580 #[test]
581 fn test_types_i128() {
582 std::env::set_var("ENV_FLAGS_TEST_TYPES_I128_POS", "1020304995959399");
583 std::env::set_var("ENV_FLAGS_TEST_TYPES_I128_NEG", "-1020304995959399");
584 env_flags! {
585 ENV_FLAGS_TEST_TYPES_I128_POS: i128;
586 ENV_FLAGS_TEST_TYPES_I128_NEG: i128;
587 };
588 assert_eq!(*ENV_FLAGS_TEST_TYPES_I128_POS, 1020304995959399);
589 assert_eq!(*ENV_FLAGS_TEST_TYPES_I128_NEG, -1020304995959399);
590 }
591
592 #[test]
593 fn test_types_isize() {
594 std::env::set_var("ENV_FLAGS_TEST_TYPES_ISIZE_POS", "29294");
595 std::env::set_var("ENV_FLAGS_TEST_TYPES_ISIZE_NEG", "-29294");
596 env_flags! {
597 ENV_FLAGS_TEST_TYPES_ISIZE_POS: isize;
598 ENV_FLAGS_TEST_TYPES_ISIZE_NEG: isize;
599 };
600 assert_eq!(*ENV_FLAGS_TEST_TYPES_ISIZE_POS, 29294);
601 assert_eq!(*ENV_FLAGS_TEST_TYPES_ISIZE_NEG, -29294);
602 }
603
604 #[test]
605 fn test_types_u8() {
606 std::env::set_var("ENV_FLAGS_TEST_TYPES_U8", "10");
607 env_flags! {
608 ENV_FLAGS_TEST_TYPES_U8: u8;
609 };
610 assert_eq!(*ENV_FLAGS_TEST_TYPES_U8, 10);
611 }
612
613 #[test]
614 fn test_types_u16() {
615 std::env::set_var("ENV_FLAGS_TEST_TYPES_U16", "7432");
616 env_flags! {
617 ENV_FLAGS_TEST_TYPES_U16: u16;
618 };
619 assert_eq!(*ENV_FLAGS_TEST_TYPES_U16, 7432);
620 }
621
622 #[test]
623 fn test_types_u32() {
624 std::env::set_var("ENV_FLAGS_TEST_TYPES_U32", "305528");
625 env_flags! {
626 ENV_FLAGS_TEST_TYPES_U32: u32;
627 };
628 assert_eq!(*ENV_FLAGS_TEST_TYPES_U32, 305528);
629 }
630
631 #[test]
632 fn test_types_u64() {
633 std::env::set_var("ENV_FLAGS_TEST_TYPES_U64", "123456789");
634 env_flags! {
635 ENV_FLAGS_TEST_TYPES_U64: u64;
636 };
637 assert_eq!(*ENV_FLAGS_TEST_TYPES_U64, 123456789);
638 }
639
640 #[test]
641 fn test_types_u128() {
642 std::env::set_var("ENV_FLAGS_TEST_TYPES_U128", "2919239");
643 env_flags! {
644 ENV_FLAGS_TEST_TYPES_U128: u128;
645 };
646 assert_eq!(*ENV_FLAGS_TEST_TYPES_U128, 2919239);
647 }
648
649 #[test]
650 fn test_types_usize() {
651 std::env::set_var("ENV_FLAGS_TEST_TYPES_USIZE", "2939");
652 env_flags! {
653 ENV_FLAGS_TEST_TYPES_USIZE: usize;
654 };
655 assert_eq!(*ENV_FLAGS_TEST_TYPES_USIZE, 2939);
656 }
657
658 #[test]
659 fn test_types_ipaddr() {
660 std::env::set_var("ENV_FLAGS_TEST_TYPES_IPADDR", "0.0.0.0");
661 env_flags! {
662 ENV_FLAGS_TEST_TYPES_IPADDR: IpAddr;
663 };
664 assert_eq!(*ENV_FLAGS_TEST_TYPES_IPADDR, {
665 let ip: Ipv4Addr = "0.0.0.0".parse().unwrap();
666 ip
667 });
668 }
669
670 #[test]
671 fn test_types_ipv4addr() {
672 std::env::set_var("ENV_FLAGS_TEST_TYPES_IPV4ADDR", "127.0.0.1");
673 env_flags! {
674 ENV_FLAGS_TEST_TYPES_IPV4ADDR: Ipv4Addr;
675 };
676 assert_eq!(*ENV_FLAGS_TEST_TYPES_IPV4ADDR, {
677 let ip: Ipv4Addr = "127.0.0.1".parse().unwrap();
678 ip
679 });
680 }
681
682 #[test]
683 fn test_types_ipv6addr() {
684 std::env::set_var(
685 "ENV_FLAGS_TEST_TYPES_IPV6ADDR",
686 "2001:0000:130F:0000:0000:09C0:876A:130B",
687 );
688 env_flags! {
689 ENV_FLAGS_TEST_TYPES_IPV6ADDR: Ipv6Addr;
690 };
691 assert_eq!(*ENV_FLAGS_TEST_TYPES_IPV6ADDR, {
692 let ip: Ipv6Addr = "2001:0000:130F:0000:0000:09C0:876A:130B".parse().unwrap();
693 ip
694 });
695 }
696
697 #[test]
698 fn test_types_socketaddr() {
699 std::env::set_var("ENV_FLAGS_TEST_TYPES_SOCKETADDR", "192.168.0.1:8080");
700 env_flags! {
701 ENV_FLAGS_TEST_TYPES_SOCKETADDR: SocketAddr;
702 };
703 assert_eq!(
704 *ENV_FLAGS_TEST_TYPES_SOCKETADDR,
705 "192.168.0.1:8080".parse().unwrap()
706 );
707 }
708
709 #[test]
710 fn test_types_pathbuf() {
711 std::env::set_var("ENV_FLAGS_TEST_TYPES_PATHBUF", "/var/lib/file.txt");
712 env_flags! {
713 ENV_FLAGS_TEST_TYPES_PATHBUF: PathBuf;
714 }
715 assert_eq!(
716 *ENV_FLAGS_TEST_TYPES_PATHBUF,
717 PathBuf::from("/var/lib/file.txt")
718 );
719 }
720
721 #[test]
722 fn test_types_option() {
723 std::env::set_var("ENV_FLAGS_TEST_OPTION_SET", "cat");
724 env_flags! {
725 ENV_FLAGS_TEST_OPTION_UNSET: Option<&str> = None;
726 ENV_FLAGS_TEST_OPTION_SET: Option<&str> = None;
727 };
728 assert!(ENV_FLAGS_TEST_OPTION_UNSET.is_none());
729 assert_eq!(*ENV_FLAGS_TEST_OPTION_SET, Some("cat"));
730 }
731
732 #[test]
733 fn test_types_vec() {
734 std::env::set_var("ENV_FLAGS_TEST_VEC", "1,2,3,4");
735 env_flags! {
736 ENV_FLAGS_TEST_VEC: Vec<u32>;
737 };
738 assert_eq!(*ENV_FLAGS_TEST_VEC, vec![1, 2, 3, 4]);
739 }
740
741 #[test]
742 fn test_types_bool() {
743 std::env::set_var("ENV_FLAGS_TEST_BOOL_TRUE", "true");
744 std::env::set_var("ENV_FLAGS_TEST_BOOL_FALSE", "false");
745 std::env::set_var("ENV_FLAGS_TEST_BOOL_TRUE_UPPER", "TRUE");
746 std::env::set_var("ENV_FLAGS_TEST_BOOL_FALSE_UPPER", "FALSE");
747 std::env::set_var("ENV_FLAGS_TEST_BOOL_0", "0");
748 std::env::set_var("ENV_FLAGS_TEST_BOOL_1", "1");
749 env_flags! {
750 ENV_FLAGS_TEST_BOOL_TRUE: bool;
751 ENV_FLAGS_TEST_BOOL_FALSE: bool;
752 ENV_FLAGS_TEST_BOOL_TRUE_UPPER: bool;
753 ENV_FLAGS_TEST_BOOL_FALSE_UPPER: bool;
754 ENV_FLAGS_TEST_BOOL_0: bool;
755 ENV_FLAGS_TEST_BOOL_1: bool;
756 };
757 assert_eq!(*ENV_FLAGS_TEST_BOOL_TRUE, true);
758 assert_eq!(*ENV_FLAGS_TEST_BOOL_FALSE, false);
759 assert_eq!(*ENV_FLAGS_TEST_BOOL_TRUE_UPPER, true);
760 assert_eq!(*ENV_FLAGS_TEST_BOOL_FALSE_UPPER, false);
761 assert_eq!(*ENV_FLAGS_TEST_BOOL_0, false);
762 assert_eq!(*ENV_FLAGS_TEST_BOOL_1, true);
763 }
764
765 #[test]
766 fn test_deref() {
767 env_flags! {
768 ENV_FLAGS_TEST_DEREF: &str = "hello";
769 };
770
771 fn print_str(s: &str) {
772 println!("{}", s);
773 }
774
775 print_str(&ENV_FLAGS_TEST_DEREF);
776 print_str(*ENV_FLAGS_TEST_DEREF);
777 }
778
779 #[test]
780 fn test_debug() {
781 env_flags! {
782 ENV_FLAGS_TEST_DEBUG: &str = "cat";
783 };
784
785 let str = format!("{:?}", ENV_FLAGS_TEST_DEBUG);
786 assert_eq!(str, "\"cat\"");
787 }
788
789 #[test]
790 fn test_display() {
791 env_flags! {
792 ENV_FLAGS_TEST_DEBUG: &str = "cat";
793 };
794
795 let str = format!("{}", ENV_FLAGS_TEST_DEBUG);
796 assert_eq!(str, "cat");
797 }
798}