pub mod probe;
#[doc(hidden)]
pub use paste as __paste;
#[must_use]
pub fn none<T>() -> Option<T> {
None
}
#[must_use]
pub fn clamp<T: PartialOrd>(v: T, lo: T, hi: T) -> T {
if v < lo {
lo
} else if v > hi {
hi
} else {
v
}
}
#[macro_export]
macro_rules! defaxes {
($(
$(#[$meta:meta])*
$name:ident : $ty:ty = $fallback:expr => $probe:expr ;
)+) => {
$( $crate::__paste::paste! {
$(#[$meta])*
#[doc = concat!("\n\nSafe fallback for the `", stringify!($name), "` axis.")]
pub const [<FALLBACK_ $name:upper>]: $ty = $fallback;
$(#[$meta])*
#[doc = concat!("\n\nBest-effort probe for `", stringify!($name), "`; `None` when unanswerable.")]
#[must_use]
pub fn [<detect_ $name>]() -> ::core::option::Option<$ty> {
($probe)()
}
#[doc = concat!("Resolve `", stringify!($name), "`: detection, else [`FALLBACK_", stringify!([<$name:upper>]), "`].")]
#[must_use]
pub fn [<detect_ $name _or_fallback>]() -> $ty {
[<detect_ $name>]().unwrap_or([<FALLBACK_ $name:upper>])
}
} )+
};
}
#[cfg(test)]
mod tests {
crate::defaxes! {
widget_count: u32 = 7 => || Some(42);
gizmos: u32 = 3 => crate::none;
flavor: &'static str = "nord" => || Some("dracula");
}
#[test]
fn detection_wins_when_some() {
assert_eq!(detect_widget_count_or_fallback(), 42);
assert_eq!(detect_flavor_or_fallback(), "dracula");
}
#[test]
fn fallback_when_none() {
assert!(detect_gizmos().is_none());
assert_eq!(detect_gizmos_or_fallback(), 3);
}
#[test]
fn fallback_consts_pinned() {
assert_eq!(FALLBACK_WIDGET_COUNT, 7);
assert_eq!(FALLBACK_GIZMOS, 3);
assert_eq!(FALLBACK_FLAVOR, "nord");
}
#[test]
fn clamp_bounds() {
assert_eq!(crate::clamp(5, 0, 10), 5);
assert_eq!(crate::clamp(-3, 0, 10), 0);
assert_eq!(crate::clamp(99, 0, 10), 10);
}
}