macro_rules! storage_of {
($id:ident, true) => { bool };
($id:ident, false) => { bool };
($id:ident, [ $($value: expr),* ]) => { std::collections::HashSet<String> };
($id:ident, $(=int $check: expr;)+ $_: expr) => { u64 };
($id:ident, $(=enum $k: ident;)+ $_: ident) => { $crate::defaults::enums::$id };
($id:ident, None) => { Option<Box<str>> };
($id:ident, $_: expr) => { Box<str> };
}
macro_rules! referent_of {
($id:ident, true) => { bool };
($id:ident, false) => { bool };
($id:ident, [ $($value: expr),* ]) => { &std::collections::HashSet<String> };
($id:ident, $(=int $check: expr;)+ $_: expr) => { u64 };
($id:ident, $(=enum $k: ident;)+ $_: ident) => { $crate::defaults::enums::$id };
($id:ident, None) => { Option<&str> };
($id:ident, $_: expr) => { &str };
}
macro_rules! initializer_of {
($id:ident, true) => { true };
($id:ident, false) => { false };
($id:ident, [ $($value: expr),* ]) => { [$($value),*].into_iter().map(|s: &str| s.to_string()).collect::<std::collections::HashSet<_>>() };
($id:ident, $(=int $check: expr;)+ $value: expr) => { $value };
($id:ident, $(=enum $k: ident;)+ $value: ident) => { $crate::defaults::enums::$id::$value };
($id:ident, None) => { None };
($id:ident, $value: expr) => { $value.into() };
($id:ident, $($_: tt)*) => { return None };
}
macro_rules! result_of {
($id:expr, true) => {
$id
};
($id:expr, false) => {
$id
};
($id:expr, [ $($value: expr),* ]) => {
&$id
};
($id:expr, $(=value $k: expr;)+ $_: expr) => {
$id
};
($id:expr, None) => {
$id.as_deref()
};
($id:expr, $_: expr) => {
$id.as_ref()
};
}
macro_rules! modifier_of {
($id:ident, true) => {
$crate::defaults::SettingKind::Flag(Box::new(move |obj: &mut Settings| obj.$id = true))
};
($id:ident, false) => {
$crate::defaults::SettingKind::Flag(Box::new(move |obj: &mut Settings| obj.$id = true))
};
($id:ident, [ $($value: expr),* ]) => {
$crate::defaults::SettingKind::List(|mode, list| {
Box::new(move |obj: &mut Settings| match mode {
ListMode::Set => obj.$id = list.into_iter().collect(),
ListMode::Add => obj.$id.extend(list),
ListMode::Del => {
for key in list {
obj.$id.remove(&key);
}
}
})
})
};
($id:ident, =int $first:literal ..= $last: literal $(@ $radix: literal)?; $value: expr) => {
#[allow(clippy::from_str_radix_10)]
$crate::defaults::SettingKind::Integer(|text| {
u64::from_str_radix(text, 10$(*0 + $radix)?)
.ok()
.filter(|val| ($first ..= $last).contains(val))
.map(|i| {
Box::new(move |obj: &mut Settings| obj.$id = i) as SettingsModifier
})
})
};
($id:ident, =int $fn: expr; $value: expr) => {
$crate::defaults::SettingKind::Integer(|text| {
$fn(&text).map(|i| {
Box::new(move |obj: &mut Settings| obj.$id = i) as SettingsModifier
})
})
};
($id:ident, $(=int $check: expr;)+ $value: expr) => { compile_error!("bla") };
($id:ident, $(=enum $key: ident;)+ $value: ident) => {
$crate::defaults::SettingKind::Text(|key| match key {
$(
stringify!($key) => {
Some(Box::new(move |obj: &mut Settings| obj.$id = $crate::defaults::enums::$id::$key))
},
)*
_ => None,
})
};
($id:ident, None) => {
$crate::defaults::SettingKind::Text(|text| {
let text = text.into();
Some(Box::new(move |obj: &mut Settings| obj.$id = Some(text)))
})
};
($id:ident, $value: expr) => {
$crate::defaults::SettingKind::Text(|text| {
let text = text.into();
Some(Box::new(move |obj: &mut Settings| obj.$id = text))
})
};
}
macro_rules! has_standard_negator {
(true) => {
true
};
(false) => {
true
};
([$($_: expr),*]) => {
true
};
($($_: tt)*) => {
false
};
}
macro_rules! ifdef {
(; $then: expr; $else: expr) => {
$else
};
($($_: expr)+; $then: expr; $else: expr) => {
$then
};
}
macro_rules! emit {
(ignored; $($def: tt)*) => { };
( ; $($def: tt)*) => { $($def)* };
}
macro_rules! defaults {
($($name:ident = $value:tt $((!= $negate:tt))? $([$($key:ident),*])? $([$first:literal ..= $last:literal$(; radix: $radix: expr)?])? $({$fn: expr})? $(#$attribute:ident)?)*) => {
#[allow(non_camel_case_types)]
mod enums {
$($(
#[derive(Clone,Copy,Debug,Default)]
#[cfg_attr(test, derive(PartialEq, Eq))]
pub enum $name { #[default] $($key),* }
)?)*
}
#[derive(Clone)]
pub struct Settings {
$($name: storage_of!($name, $(=int $fn;)?$(=int $first;)?$($(=enum $key;)*)? $value)),*
}
impl Settings {
$(
emit! { $($attribute)?;
pub fn $name(&self) -> referent_of!($name, $(=int $fn;)?$(=int $first;)?$($(=enum $key;)*)? $value) {
result_of!(self.$name, $(=value $fn;)?$(=value $first;)?$($(=value $key;)*)? $value)
}
}
)*
}
impl Default for Settings {
fn default() -> Self {
Self {
$($name: initializer_of!($name, $(=int $fn;)?$(=int $first;)?$($(=enum $key;)*)? $value)),*
}
}
}
pub fn negate(name: &str) -> Option<SettingsModifier> {
match name {
$(
stringify!($name) if ifdef!($($negate)?; true; has_standard_negator!($value)) => {
let value = ifdef!($($negate)?;
initializer_of!($name, $(=int $fn;)?$(=int $first;)?$($(=enum $key;)*)? $($negate)?);
Default::default()
);
Some(Box::new(move |obj: &mut Settings| obj.$name = value))
},
)*
_ => None
}
}
pub fn set(name: &str) -> Option<SettingKind> {
match name {
$(
stringify!($name) => Some(modifier_of!($name, $(=int $fn;)?$(=int $first ..= $last $(@ $radix)?;)?$($(=enum $key;)*)? $value)),
)*
_ => None,
}
}
};
}
pub(super) use defaults;
pub(super) use emit;
pub(super) use has_standard_negator;
pub(super) use ifdef;
pub(super) use initializer_of;
pub(super) use modifier_of;
pub(super) use referent_of;
pub(super) use result_of;
pub(super) use storage_of;