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