macro_rules! write_u8 {
($w:expr, $val:expr) => {
$w.write_all(&[$val]).context(wr!())
};
}
macro_rules! clamp {
(
$(#[$meta:meta])*
$symbol:ident, $inner_type:ty, $min:expr, $max:expr, $default:expr, $visibility:vis
) => {
$(#[$meta])*
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
$visibility struct $symbol($inner_type);
impl Default for $symbol {
fn default() -> Self {
Self::new($default)
}
}
impl $symbol {
#[allow(dead_code)]
$visibility const fn new(value: $inner_type) -> Self {
let (clamped, _) = Self::clamp(value);
Self(clamped)
}
#[allow(dead_code)]
$visibility fn get(&self) -> $inner_type {
self.0
}
#[allow(dead_code)]
$visibility fn set(&mut self, value: $inner_type) -> bool {
let (clamped, result) = Self::clamp(value);
self.0 = clamped;
result
}
#[allow(unused_comparisons)]
const fn clamp(value: $inner_type) -> ($inner_type, bool) {
if value < $min {
($min, false)
} else if value > $max {
($max, false)
} else {
(value, true)
}
}
}
impl From<$inner_type> for $symbol {
fn from(value: $inner_type) -> Self {
Self::new(value)
}
}
impl From<$symbol> for $inner_type {
fn from(value: $symbol) -> $inner_type {
value.0
}
}
impl std::fmt::Display for $symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
};
}
#[test]
#[allow(clippy::disallowed_names)]
fn clamp_test() {
clamp!(Foo, u8, 1, 16, 1, pub);
let foo: Foo = 0u8.into();
let foo_val: u8 = foo.into();
assert_eq!(1, foo_val);
let fmted = format!("{}", Foo::new(6));
assert_eq!("6", fmted.as_str());
}