#[doc(hidden)]
#[macro_export]
macro_rules! make_config_impl {
(@__field_config_ty $Config:ty) => {
$Config
};
(@__field_config_ty
var_name: $_var_name:literal
$(, $($rest:tt)*)?
) => {
$crate::__private::make_config_impl!(@__field_config_ty_layers $($($rest)*)?)
};
(@__field_config_ty_layers layers: [] $($_rest:tt)*) => {
$crate::layers::TextVar
};
(@__field_config_ty_layers layers: [$($layers_tt:tt)+] $($_rest:tt)*) => {
$crate::__private::make_config_impl!(@__field_config_ty_layers_content $($layers_tt)+)
};
(@__field_config_ty_layers $($_rest:tt)*) => {
$crate::layers::TextVar
};
(@__field_config_ty_layers_content
$($func_ident:ident $(<$($func_gen:ty),* $(,)?>)? ($($func_content:tt)*)),* $(,)?
) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([ $func_ident $(<$($func_gen),*>)? ($($func_content)*) ])*]
$crate::layers::TextVar
)
};
(@__field_config_ty_layer [] $($wrapped:tt)* ) => {
$($wrapped)*
};
(@__field_config_ty_layer [[cached()] $([$($rest:tt)*])*] $($wrapped:tt)* ) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([$($rest)*])*]
$crate::layers::Cached<$($wrapped)*>
)
};
(@__field_config_ty_layer [[file_read()] $([$($rest:tt)*])*] $($wrapped:tt)* ) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([$($rest)*])*]
$crate::layers::FileRead<$($wrapped)*>
)
};
(@__field_config_ty_layer [[parsed<$parse_ty:ty>($($_content:tt)*)] $([$($rest:tt)*])*] $($wrapped:tt)* ) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([$($rest)*])*]
$crate::layers::Parsed<$parse_ty, $($wrapped)*>
)
};
(@__field_config_ty_layer [[parsed_from_str<$parse_ty:ty>()] $([$($rest:tt)*])*] $($wrapped:tt)* ) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([$($rest)*])*]
$crate::layers::Parsed<$parse_ty, $($wrapped)*>
)
};
(@__field_config_ty_layer [[or_default_val($($_content:tt)*)] $([$($rest:tt)*])*] $($wrapped:tt)* ) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([$($rest)*])*]
$crate::layers::OrDefault<$($wrapped)*>
)
};
(@__field_config_ty_layer [[or_default()] $([$($rest:tt)*])*] $($wrapped:tt)* ) => {
$crate::__private::make_config_impl!(@__field_config_ty_layer
[$([$($rest)*])*]
$crate::layers::OrDefault<$($wrapped)*>
)
};
(@__field_config_def $Config:ty) => {{
<$Config as $crate::ConfigDescriptor>::define()
}};
(@__field_config_def
var_name: $var_name:literal
$(, layers: [$($layers:tt)*])?
$(, description: $description:literal)?
$(, default_val_fmt: $default_val_fmt:literal)?
$(,)?
) => {{
let __config = $crate::layers::TextVar::from_var_name($var_name)
$(.description($description))?
$(.default_fmt_val($default_val_fmt))?;
$crate::__private::make_config_impl!(@__field_config_def_layers __config $($($layers)*)?)
}};
(@__field_config_def_layers $binding:ident) => {
$binding
};
(@__field_config_def_layers $binding:ident
$head:ident $(<$($head_gen_content:ty)*>)? ($($head_content:tt)*)
$(, $tail:ident $(<$($tail_gen_content:ty)*>)? ($($tail_content:tt)*))* $(,)?
) => {{
let $binding = $crate::__private::make_config_impl!(@__field_config_def_layer $binding
$head $(<$($head_gen_content)*>)? ($($head_content)*)
);
$crate::__private::make_config_impl!(@__field_config_def_layers $binding
$($tail $(<$($tail_gen_content)*>)? ($($tail_content)*)),*
)
}};
(@__field_config_def_layer $binding:ident cached()) => {
$binding.cached()
};
(@__field_config_def_layer $binding:ident file_read()) => {
$binding.file_read()
};
(@__field_config_def_layer $binding:ident parsed<$parse_ty:ty>($($parse_content:tt)*)) => {
$binding.parsed::<$parse_ty>($($parse_content)*)
};
(@__field_config_def_layer $binding:ident parsed_from_str<$parse_ty:ty>()) => {
$binding.parsed_from_str::<$parse_ty>()
};
(@__field_config_def_layer $binding:ident or_default_val($($or_default_val_content:tt)*)) => {
$binding.or_default_val($($or_default_val_content)*)
};
(@__field_config_def_layer $binding:ident or_default()) => {
$binding.or_default()
};
(@__field_kind $lt:lifetime [$($head_config:tt)*] $([$($tail_config:tt)*])*) => {
$crate::__private::iter::Chain<
$crate::__private::make_config_impl!(@__field_kind_ty $lt $($head_config)*),
$crate::__private::make_config_impl!(@__field_kind $lt $([$($tail_config)*])*),
>
};
(@__field_kind $lt:lifetime) => {
$crate::__private::iter::Empty<$crate::exec::ExecResult<$lt>>
};
(@__field_kind_ty $lt:lifetime $Config:ty) => {
<<$Config as $crate::exec::ConfigInitializer>::Iter<$lt> as
$crate::__private::iter::IntoIterator>::IntoIter
};
(@__field_kind_ty $lt:lifetime var_name $($_rest:tt)*) => {
$crate::__private::iter::Once<$crate::exec::ExecResult<$lt>>
};
(@__field_kind_calls $self:ident [$head_field:ident: $($head_config:tt)*] $([$($tail:tt)*])*) => {
$crate::__private::make_config_impl!(@__field_kind_call $self $head_field $($head_config)*)
.chain($crate::__private::make_config_impl!(@__field_kind_calls $self $([$($tail)*])*))
};
(@__field_kind_calls $_self:ident) => {
$crate::__private::iter::empty::<$crate::exec::ExecResult<'_>>()
};
(@__field_kind_call $self:ident $field:ident $Config:ty) => {
<$Config as $crate::exec::ConfigInitializer>::init_raw(&$self.$field)
.into_iter()
};
(@__field_kind_call $self:ident $field:ident var_name $($_rest:tt)*) => {
$crate::__private::iter::once(
$crate::exec::ExecResult {
config: $self.$field.get_descriptor(),
error: $self.$field.try_get().err().map(From::from),
}
)
};
}
#[doc(hidden)]
pub use make_config_impl;
#[macro_export]
macro_rules! make_config {
{
$(#[$main_attr:meta])*
$vis:vis struct $Name:ident {$(
$(#[$field_attr:meta])*
$field_vis:vis $field:ident: { $($field_config:tt)* }
),* $(,)?}
} => {
$(#[$main_attr])*
$vis struct $Name {$(
$(#[$field_attr])*
$field_vis $field: $crate::__private::make_config_impl!(@__field_config_ty $($field_config)*),
)*}
const _: () = {
#[automatically_derived]
impl $crate::ConfigDescriptor for $Name {
fn define() -> Self {
#[allow(unused_imports)]
use $crate::prelude::*;
Self {$(
$field: $crate::__private::make_config_impl!(@__field_config_def $($field_config)*)
),*}
}
}
#[automatically_derived]
impl $crate::exec::ConfigInitializer for $Name {
type Iter<'a> = $crate::__private::make_config_impl!(@__field_kind
'a $([$($field_config)*])*
);
fn init_raw(&self) -> Self::Iter<'_> {
#[allow(unused_imports)]
use $crate::prelude::*;
$crate::__private::make_config_impl!(
@__field_kind_calls self $([ $field: $($field_config)* ])*
)
}
}
};
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn assert_result_iter_coherent_no_flattening() {
make_config! {
struct TestConfig {
var_a: {
var_name: "VAR_A",
},
var_b: {
var_name: "VAR_B",
},
var_c: {
var_name: "VAR_C",
layers: [
parsed_from_str<i32>(),
or_default(),
cached(),
],
description: "hello",
},
}
}
let config = TestConfig::define();
let res = config.init_raw();
itertools::assert_equal(
res.map(|res| res.config.var_name),
["VAR_A", "VAR_B", "VAR_C"],
);
}
#[test]
fn assert_result_iter_coherent_with_flattening() {
make_config! {
struct Foo {
var_a: {
var_name: "VAR_A",
},
var_b: {
var_name: "VAR_B",
},
}
}
make_config! {
struct Bar {
foo: { Foo },
var_c: {
var_name: "VAR_C",
},
var_d: {
var_name: "VAR_D",
},
}
}
let config = Bar::define();
let res = config.init_raw();
itertools::assert_equal(
res.map(|res| res.config.var_name),
["VAR_A", "VAR_B", "VAR_C", "VAR_D"],
);
}
#[cfg(debug_assertions)]
#[allow(unexpected_cfgs, unused)]
mod __assert_compiles {
make_config! {
struct Foo0 {}
}
make_config! {
pub struct Foo1 {}
}
make_config! {
pub struct Foo2 {
pub bar: { Foo1 },
}
}
make_config! {
struct Foo3 {
}
}
make_config! {
struct Foo4 {
bar: { Foo1 },
}
}
make_config! {
#[derive(Debug)]
struct Foo5 {
}
}
#[cfg(not(feature = "foo"))]
make_config! {
struct Foo6 {
bar: { Foo1 },
}
}
#[cfg(feature = "foo")]
make_config! {
struct Foo6 {
bar: { Foo2 },
}
}
make_config! {
struct Foo7 {
foo: {
var_name: "HI",
}
}
}
make_config! {
struct Foo8 {
foo: {
var_name: "HI",
layers: [
file_read(),
parsed<std::time::Duration>(|input| todo!()),
or_default(),
cached(),
],
}
}
}
make_config! {
struct Foo9 {
foo: { Foo8 },
bar: {
var_name: "HEY",
},
foobar: { Foo8 },
}
}
make_config! {
struct Foo10 {
foo: {
var_name: "HEY",
description: "hey",
default_val_fmt: "no default :(",
}
}
}
// provide description and default_fmt_val - with layers
make_config! {
struct Foo11 {
foo: {
var_name: "HEY",
layers: [cached()],
description: "hey",
default_val_fmt: "no default :(",
}
}
}
// provide description alone
make_config! {
struct Foo12 {
foo: {
var_name: "HEY",
description: "hey",
}
}
}
// provide default_val_fmt alone
make_config! {
struct Foo13 {
foo: {
var_name: "HEY",
default_val_fmt: "no default :(",
}
}
}
// empty layers
make_config! {
struct Foo14 {
foo: {
var_name: "HEY",
layers: []
}
}
}
}
}