#![feature(generic_const_exprs)]
use core::fmt::Debug;
use core::ops::{Shl, Shr};
#[derive(Debug)]
pub enum RangeError {
TooSmall,
TooLarge,
}
pub trait Num: Clone + Copy + Debug + Eq + Ord + PartialEq + PartialOrd + Sized {
type Raw: Num<Raw = Self::Raw> + Shl<u32, Output = Self::Raw> + Shr<u32, Output = Self::Raw>;
type Output<const B: u32, const S: i32>: Num<Raw = Self::Raw>;
const BITS: u32;
const SHIFT: i32;
const MIN: Self;
const MAX: Self;
const SIGNED: bool;
unsafe fn new_unchecked(val: Self::Raw) -> Self;
fn new(val: Self::Raw) -> Result<Self, RangeError> {
if val < Self::MIN.raw() {
Err(RangeError::TooSmall)
} else if val > Self::MAX.raw() {
Err(RangeError::TooLarge)
} else {
Ok(unsafe { Self::new_unchecked(val) })
}
}
fn raw(self) -> Self::Raw;
fn from_f32(val: f32) -> Result<Self, RangeError> {
assert!(val.is_finite());
if val < Self::MIN.into_f32() {
Err(RangeError::TooSmall)
} else if val > Self::MAX.into_f32() {
Err(RangeError::TooLarge)
} else {
Ok(unsafe { Self::from_f32_unchecked(val) })
}
}
unsafe fn from_f32_unchecked(val: f32) -> Self;
fn from_f64(val: f64) -> Result<Self, RangeError> {
assert!(val.is_finite());
if val < Self::MIN.into_f64() {
Err(RangeError::TooSmall)
} else if val > Self::MAX.into_f64() {
Err(RangeError::TooLarge)
} else {
Ok(unsafe { Self::from_f64_unchecked(val) })
}
}
unsafe fn from_f64_unchecked(val: f64) -> Self;
fn into_f32(self) -> f32;
fn into_f64(self) -> f64;
fn from_fp<T: Num, F: Num<Raw = T>>(val: F) -> Self
where
Self::Raw: TryFrom<T>,
{
assert!(Self::SHIFT == F::SHIFT);
assert!(Self::BITS >= F::BITS);
assert!(Self::SIGNED == F::SIGNED);
unsafe { Self::new_unchecked(val.raw().try_into().ok().unwrap()) }
}
fn into_fp<T: Num, F: Num<Raw = T>>(self) -> F
where
T: TryFrom<Self::Raw>,
{
F::from_fp(self)
}
fn add_bits<const N: u32>(self) -> Self::Output<{ Self::BITS + N }, { Self::SHIFT }>
where
[(); (Self::BITS + N) as usize]:,
{
unsafe { Self::Output::new_unchecked(self.raw()) }
}
fn set_bits<const N: u32>(self) -> Result<Self::Output<N, { Self::SHIFT }>, RangeError> {
Self::Output::new(self.raw())
}
unsafe fn set_bits_unchecked<const N: u32>(self) -> Self::Output<N, { Self::SHIFT }> {
unsafe { Self::Output::new_unchecked(self.raw()) }
}
fn saturate<const N: u32>(self) -> Self::Output<N, { Self::SHIFT }> {
match Self::Output::new(self.raw()) {
Err(RangeError::TooSmall) => Self::Output::MIN,
Err(RangeError::TooLarge) => Self::Output::MAX,
Ok(val) => val,
}
}
fn logical_shl<const N: i32>(self) -> Self::Output<{ Self::BITS }, { Self::SHIFT - N }>
where
[(); (Self::SHIFT - N) as usize]:,
{
unsafe { Self::Output::new_unchecked(self.raw()) }
}
fn logical_shr<const N: i32>(self) -> Self::Output<{ Self::BITS }, { Self::SHIFT + N }>
where
[(); (Self::SHIFT + N) as usize]:,
{
unsafe { Self::Output::new_unchecked(self.raw()) }
}
fn raw_shl<const N: u32>(self) -> Self::Output<{ Self::BITS + N }, { Self::SHIFT + N as i32 }>
where
[(); (Self::BITS + N) as usize]:,
[(); (Self::SHIFT + N as i32) as usize]:,
{
unsafe { Self::Output::new_unchecked(self.raw() << N) }
}
fn raw_shr<const N: u32>(self) -> Self::Output<{ Self::BITS - N }, { Self::SHIFT - N as i32 }>
where
[(); (Self::BITS - N) as usize]:,
[(); (Self::SHIFT - N as i32) as usize]:,
{
unsafe { Self::Output::new_unchecked(self.raw() >> N) }
}
}
mod num_impl;
pub use num_impl::*;
mod add_sub;
mod mul_div;