configuration/
lib.rs

1//! Means of configuration.
2
3/// Define a configuration.
4///
5/// ```
6/// use std::net::SocketAddr;
7/// use std::path::{Path, PathBuf};
8///
9/// configuration::define! {
10///     /// A config.
11///     Config {
12///         /// The foo config.
13///         foo: Foo
14///         where
15///             /// A foo config.
16///             Foo {
17///                 /// The bar.
18///                 bar: String = [CONFIG_FOO_BAR],
19///                 /// The buz.
20///                 buz: PathBuf = [
21///                     CONFIG_FOO_BUZ,
22///                     config_foo_buz() { "buz".into() }
23///                 ],
24///                 /// The qux.
25///                 qux: usize = [
26///                     CONFIG_FOO_QUX,
27///                     config_foo_qux() { 42 }
28///                 ],
29///             },
30///         /// The bar config.
31///         bar: Bar
32///         where
33///             /// A bar config.
34///             Bar {
35///                 /// The buz.
36///                 buz: String = [CONFIG_BAR_BUZ],
37///             },
38///         /// The buz config.
39///         buz: Buz
40///         where
41///             /// A buz config.
42///             Buz {
43///                 /// The qux.
44///                 qux: SocketAddr = [
45///                     CONFIG_BUZ_QUX,
46///                     config_buz_qux() { "0.0.0.0:80".parse().unwrap() }
47///                 ],
48///             },
49///         /// The qux.
50///         qux: String = [CONFIG_QUX],
51///     }
52/// }
53///
54/// std::env::set_var("CONFIG_FOO_BAR", "bar");
55/// std::env::set_var("CONFIG_BAR_BUZ", "buz");
56/// std::env::set_var("CONFIG_BUZ_QUX", "127.0.0.1:80");
57/// std::env::set_var("CONFIG_QUX", "qux");
58///
59/// let config = Config::default();
60/// assert_eq!(config.foo.bar, "");
61/// assert_eq!(config.buz.qux, "0.0.0.0:80".parse().unwrap());
62/// assert_eq!(config.qux, "");
63///
64/// let config = Config::try_default().unwrap();
65/// assert_eq!(config.foo.bar, "bar");
66/// assert_eq!(config.foo.buz, Path::new("buz"));
67/// assert_eq!(config.foo.qux, 42);
68/// assert_eq!(config.bar.buz, "buz");
69/// assert_eq!(config.buz.qux, "127.0.0.1:80".parse().unwrap());
70/// assert_eq!(config.qux, "qux");
71/// ```
72#[macro_export]
73macro_rules! define {
74    (
75        $(#[$struct_attribute:meta])*
76        $struct:ident {
77            $(
78                $(#[$field_attribute:meta])*
79                $field:ident:
80                $type:ty
81                $(
82                    where
83                    $(#[$type_attribute:meta])*
84                    $inner:ident {
85                        $($nested:tt)+
86                    }
87                )?
88                $(= [
89                    $default_variable:ident $(,)?
90                    $(
91                        $default_function:ident ()
92                        $default_block:block
93                    )?
94                ])?,
95            )+
96        }
97    ) => (
98        $(#[$struct_attribute])*
99        #[derive(Clone, Debug)]
100        pub struct $struct {
101            $(
102                $(#[$field_attribute])*
103                pub $field: $type,
104            )+
105        }
106
107        impl $struct {
108            /// Create an instance from the environment.
109            pub fn try_default() -> std::io::Result<Self> {
110                Ok(Self {
111                    $(
112                        $field: $crate::define!(
113                            @try_default
114                            $type [$($inner)?] $($default_variable $($default_function())?)?
115                        ),
116                    )+
117                })
118            }
119        }
120
121        impl Default for $struct {
122            fn default() -> Self {
123                Self {
124                    $(
125                        $field: $crate::define!(
126                            @default
127                            $type [$($inner)?] $($default_variable $($default_function())?)?
128                        ),
129                    )+
130                }
131            }
132        }
133
134        $(
135            $(
136                $(
137                    #[inline]
138                    fn $default_function() -> $type $default_block
139                )?
140            )?
141        )+
142
143        $(
144            $(
145                $crate::define! {
146                    $(#[$type_attribute])*
147                    $inner {
148                        $($nested)+
149                    }
150                }
151            )?
152        )+
153    );
154    (@default $type:ty []) => (
155        <$type>::default()
156    );
157    (@default $type:ty [$inner:ident]) => (
158        <$type>::default()
159    );
160    (@default $type:ty [$($inner:ident)?] $variable:ident) => (
161        <$type>::default()
162    );
163    (@default $type:ty [$($inner:ident)?] $variable:ident $function:ident ()) => (
164        $function()
165    );
166    (@default $type:ty [$($inner:ident)?] $function:ident ()) => (
167        $function()
168    );
169    (@try_default $type:ty []) => (
170        <$type>::default()
171    );
172    (@try_default $type:ty [$inner:ident]) => (
173        <$type>::try_default()?
174    );
175    (@try_default $type:ty [$($inner:ident)?] $variable:ident) => (
176        match std::env::var(stringify!($variable)) {
177            Ok(value) => std::str::FromStr::from_str(&value).map_err(|error| std::io::Error::other(error))?,
178            _ => <$type>::default(),
179        }
180    );
181    (@try_default $type:ty [$($inner:ident)?] $variable:ident $function:ident ()) => (
182        match std::env::var(stringify!($variable)) {
183            Ok(value) => std::str::FromStr::from_str(&value).map_err(|error| std::io::Error::other(error))?,
184            _ => $function(),
185        }
186    );
187    (@try_default $type:ty [$($inner:ident)?] $function:ident ()) => (
188        $function()
189    );
190}