I am writing a library for fun, which will include a FixedPoint struct for fixed-point arithmetic.
struct FixedPoint<const D: u8, T>
The D parameter stands for how many bits are after the point. However I am restricting the values of it because it must be less than or equal to the number of bits of T:
struct Guard<const G: bool>;
trait Protect {}
impl Protect for Guard<true> {}
#[derive(Eq, Ord, Clone, Copy)]
struct FixedPoint<const D: u8, T>
where
T: Shr<u8, Output = T> + Copy,
Guard<{ D as usize <= std::mem::size_of::<T>() * 8 }>: Protect,
So far, this works but I ran into trouble implementing Add:
impl<const D: u8, const E: u8, T> Add<FixedPoint<E, T>> for FixedPoint<D, T>
where
T: Shr<u8, Output = T> + Add<T, Output = T> + Copy,
Guard<{ D as usize <= std::mem::size_of::<T>() * 8 }>: Protect,
Guard<{ E as usize <= std::mem::size_of::<T>() * 8 }>: Protect,
{
type Output = FixedPoint<???, T>;
fn add(self, rhs: FixedPoint<E, T>) -> Self::Output {
todo!()
}
}
The Output type should have max(D, E) bits after the point, so I tried a const fn:
const fn const_max(a: u8, b: u8) -> u8 {
if a > b {
a
} else {
b
}
}
// --snip--
type Output = FixedPoint<{ util::const_max(D, E) }, T>;
// --snip--
However this way the compiler can't know that the result of const_max will satisfy the Guard.
Is there any way to make this work without removing the Guard?
Or is there a better way to do the compile-time check of D?