Unnamed repository; edit this file 'description' to name the repository.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/// This macro allows specifiying a trait of related config
/// options with a struct like syntax. From that information
/// two things are generated:
///
/// * A `init_config` function that registers the config options with the
///   `OptionRegistry` registry.
/// * A **trait** definition with an accessor for every config option that is
///   implemented for `OptionManager`.
///
/// The accessors on the trait allow convenient statically typed access to
/// config fields. The accessors return `Guard<T>` (which allows derferecning to
/// &T). Any type that implements copy can be returned as a copy instead by
/// specifying `#[read = copy]`. Collections like `List<T>` and `String` are not
/// copy However, they usually implement deref (to &[T] and &str respectively).
/// Working with the dereferneced &str/&[T] is more convenient then &String and &List<T>. The
/// accessor will return these if `#[read = deref]` is specified.
///
/// The doc comments will be retained for the accessors and also stored in the
/// option registrry for dispaly in the UI and documentation.
///
/// The name of a config option can be changed with #[name = "<name>"],
/// otherwise the name of the field is used directly. The OptionRegistry
/// automatically converts all names to kebab-case so a name attribute is only
/// required if the name is supposed to be significantly altered.
///
/// In some cases more complex validation may be necssary. In that case the
/// valiidtator can be provided with an exprission that implements the `Validator`
/// trait: `#[validator = create_validator()]`.
#[macro_export]
macro_rules! options {
    (
        $(use $use: ident::*;)*
        $($(#[$($meta: tt)*])* struct $ident: ident {
            $(
                $(#[doc = $option_desc: literal])*
                $(#[name = $option_name: literal])?
                $(#[validator = $option_validator: expr])?
                $(#[read = $($extra: tt)*])?
                $option: ident: $ty: ty = $default: expr
            ),+$(,)?
        })+
    ) => {
        $(pub use $use::*;)*
        $($(#[$($meta)*])* pub trait $ident {
            $(
                $(#[doc = $option_desc])*
                fn $option(&self) -> $crate::options!(@ret_ty $($($extra)*)? $ty);
            )+
        })+
        pub fn init_config(registry: &mut $crate::OptionRegistry) {
            $($use::init_config(registry);)*
            $($(
                let name = $crate::options!(@name $option $($option_name)?);
                let docs = concat!("" $(,$option_desc,)" "*);
                $crate::options!(@register registry name docs $default, $ty $(,$option_validator)?);
            )+)+
        }
        $(impl $ident for $crate::OptionManager {
            $(
                $(#[doc = $option_desc])*
                fn $option(&self) -> $crate::options!(@ret_ty $($($extra)*)? $ty) {
                    let name = $crate::options!(@name $option $($option_name)?);
                    $crate::options!(@get $($($extra)*)? self, $ty, name)
                }
            )+
        })+
    };
    (@register $registry: ident $name: ident $desc: ident $default: expr, $ty:ty) => {{
        use $crate::IntoTy;
        let val: $ty = $default.into_ty();
        $registry.register($name, $desc, val);
    }};
    (@register $registry: ident $name: ident $desc: ident  $default: expr, $ty:ty, $validator: expr) => {{
        use $crate::IntoTy;
        let val: $ty = $default.into_ty();
        $registry.register_with_validator($name, $desc, val, $validator);
    }};
    (@name $ident: ident) => {
        ::std::stringify!($ident)
    };
    (@name $ident: ident $name: literal) => {
        $name
    };
    (@ret_ty copy $ty: ty) => {
        $ty
    };
    (@ret_ty map($fn: expr, $ret_ty: ty) $ty: ty) => {
        $ret_ty
    };
    (@ret_ty fold($init: expr, $fn: expr, $ret_ty: ty) $ty: ty) => {
        $ret_ty
    };
    (@ret_ty deref $ty: ty) => {
        $crate::Guard<'_, <$ty as ::std::ops::Deref>::Target>
    };
    (@ret_ty $ty: ty) => {
        $crate::Guard<'_, $ty>
    };
    (@get map($fn: expr, $ret_ty: ty) $config: ident, $ty: ty, $name: ident) => {
        let val = $config.get::<$ty>($name);
        $fn(val)
    };
    (@get fold($init: expr, $fn: expr, $ret_ty: ty) $config: ident, $ty: ty, $name: ident) => {
        $config.get_folded::<$ty, $ret_ty>($name, $init, $fn)
    };
    (@get copy $config: ident, $ty: ty, $name: ident) => {
        *$config.get::<$ty>($name)
    };
    (@get deref $config: ident, $ty: ty, $name: ident) => {
        $config.get_deref::<$ty>($name)
    };
    (@get $config: ident, $ty: ty, $name: ident) => {
        $config.get::<$ty>($name)
    };
}

#[macro_export]
macro_rules! config_serde_adapter {
    ($ty: ident) => {
        impl $crate::Ty for $ty {
            fn to_value(&self) -> $crate::Value {
                $crate::to_value(self).unwrap()
            }
            fn from_value(val: $crate::Value) -> ::anyhow::Result<Self> {
                let val = $crate::from_value(val)?;
                Ok(val)
            }
        }
    };
}