#![warn(missing_docs)]
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
extern crate alloc;
use core::fmt::{Debug, Formatter};
#[cfg(feature = "serde")]
pub mod serde;
pub use div_int_procmacro::div_int;
#[derive(Eq, PartialEq, Default, Ord, PartialOrd, Hash, Clone, Copy)]
pub struct DivInt<N, const D: u64>(N);
impl<N, const D: u64> DivInt<N, D> {
pub const fn from_numerator(n: N) -> Self {
Self(n)
}
}
impl<N: FromF64Approx, const D: u64> DivInt<N, D> {
pub fn from_f64_approx(val: f64) -> Option<Self> {
Some(Self::from_numerator(N::from_f64_approx(val * (D as f64))?))
}
}
impl<N: Into<f64>, const D: u64> From<DivInt<N, D>> for f64 {
fn from(value: DivInt<N, D>) -> Self {
value.0.into() / (D as f64)
}
}
impl<N: Copy + Into<f64>, const D: u64> DivInt<N, D> {
pub fn to_f64(self) -> f64 {
self.0.into() / (D as f64)
}
}
impl<N: Copy, const D: u64> DivInt<N, D> {
pub const fn numerator(self) -> N {
self.0
}
pub const fn denominator(self) -> u64 {
D
}
}
impl<N: Debug, const D: u64> Debug for DivInt<N, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.write_str("div_int!(")?;
self.0.fmt(f)?;
f.write_str(" / ")?;
D.fmt(f)?;
f.write_str(")")
}
}
impl<N: Copy + Into<f64>, const D: u64> core::fmt::Display for DivInt<N, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
core::fmt::Display::fmt(&self.to_f64(), f)
}
}
macro_rules! impl_core_op {
($op:ident, $op_ident:ident) => {
impl<N: core::ops::$op, const D: u64> core::ops::$op for DivInt<N, D> {
type Output = DivInt<N::Output, D>;
fn $op_ident(self, rhs: Self) -> Self::Output {
DivInt::<N::Output, D>::from_numerator(self.0.$op_ident(rhs.0))
}
}
};
}
impl_core_op!(Add, add);
impl_core_op!(Sub, sub);
macro_rules! impl_core_assign_op {
($op:ident, $op_ident:ident) => {
impl<N: core::ops::$op, const D: u64> core::ops::$op for DivInt<N, D> {
fn $op_ident(&mut self, rhs: Self) {
self.0.$op_ident(rhs.0);
}
}
};
}
impl_core_assign_op!(AddAssign, add_assign);
impl_core_assign_op!(SubAssign, sub_assign);
impl<N: core::ops::Neg, const D: u64> core::ops::Neg for DivInt<N, D> {
type Output = DivInt<N::Output, D>;
fn neg(self) -> Self::Output {
DivInt::<N::Output, D>::from_numerator(self.0.neg())
}
}
impl<N: core::ops::Shr, const D: u64> core::ops::Shr for DivInt<N, D> {
type Output = DivInt<N::Output, D>;
fn shr(self, rhs: Self) -> Self::Output {
DivInt::<N::Output, D>::from_numerator(self.0.shr(rhs.0))
}
}
impl<N: core::ops::Shl, const D: u64> core::ops::Shl for DivInt<N, D> {
type Output = DivInt<N::Output, D>;
fn shl(self, rhs: Self) -> Self::Output {
DivInt::<N::Output, D>::from_numerator(self.0.shl(rhs.0))
}
}
impl<N: num_traits::WrappingAdd, const D: u64> DivInt<N, D> {
pub fn wrapping_add(self, other: Self) -> Self {
Self(self.0.wrapping_add(&other.0))
}
}
impl<N: num_traits::WrappingSub, const D: u64> DivInt<N, D> {
pub fn wrapping_sub(self, other: Self) -> Self {
Self(self.0.wrapping_sub(&other.0))
}
}
impl<N: num_traits::WrappingNeg, const D: u64> DivInt<N, D> {
pub fn wrapping_neg(self) -> Self {
Self(self.0.wrapping_neg())
}
}
impl<N: num_traits::CheckedAdd, const D: u64> DivInt<N, D> {
pub fn checked_add(self, other: Self) -> Option<Self> {
self.0.checked_add(&other.0).map(Self)
}
}
impl<N: num_traits::CheckedSub, const D: u64> DivInt<N, D> {
pub fn checked_sub(self, other: Self) -> Option<Self> {
self.0.checked_sub(&other.0).map(Self)
}
}
impl<N: num_traits::CheckedNeg, const D: u64> DivInt<N, D> {
pub fn checked_neg(self) -> Option<Self> {
self.0.checked_neg().map(Self)
}
}
impl<N: num_traits::FromBytes, const D: u64> DivInt<N, D> {
pub fn from_be_bytes(bytes: &N::Bytes) -> Self {
Self(N::from_be_bytes(bytes))
}
pub fn from_le_bytes(bytes: &N::Bytes) -> Self {
Self(N::from_le_bytes(bytes))
}
pub fn from_ne_bytes(bytes: &N::Bytes) -> Self {
Self(N::from_ne_bytes(bytes))
}
}
impl<N: num_traits::Signed, const D: u64> DivInt<N, D> {
pub fn abs(&self) -> Self {
Self(self.0.abs())
}
pub fn is_positive(&self) -> bool {
self.0.is_positive()
}
pub fn is_negative(&self) -> bool {
self.0.is_negative()
}
}
macro_rules! impl_num_op_wrapping_trait {
($ty:ident, $op:ident) => {
impl<N: num_traits::$ty, const D: u64> num_traits::$ty for DivInt<N, D> {
fn $op(&self, v: &Self) -> Self {
Self(self.0.$op(&v.0))
}
}
}
}
impl_num_op_wrapping_trait!(WrappingAdd, wrapping_add);
impl_num_op_wrapping_trait!(WrappingSub, wrapping_sub);
impl<N: num_traits::WrappingNeg, const D: u64> num_traits::WrappingNeg for DivInt<N, D> {
fn wrapping_neg(&self) -> Self {
Self(self.0.wrapping_neg())
}
}
macro_rules! impl_num_op_checked_trait {
($ty:ident, $op:ident) => {
impl<N: num_traits::$ty, const D: u64> num_traits::$ty for DivInt<N, D> {
fn $op(&self, v: &Self) -> Option<Self> {
self.0.$op(&v.0).map(Self)
}
}
}
}
impl_num_op_checked_trait!(CheckedAdd, checked_add);
impl_num_op_checked_trait!(CheckedSub, checked_sub);
impl<N: num_traits::CheckedNeg, const D: u64> num_traits::CheckedNeg for DivInt<N, D> {
fn checked_neg(&self) -> Option<Self> {
self.0.checked_neg().map(Self)
}
}
impl<N: num_traits::FromBytes, const D: u64> num_traits::FromBytes for DivInt<N, D> {
type Bytes = N::Bytes;
fn from_be_bytes(bytes: &Self::Bytes) -> Self {
Self(N::from_be_bytes(bytes))
}
fn from_le_bytes(bytes: &Self::Bytes) -> Self {
Self(N::from_le_bytes(bytes))
}
}
pub trait FromF64Approx: Sized {
fn from_f64_approx(v: f64) -> Option<Self>;
}
macro_rules! impl_fromf64_approx {
($ty:ty, $fn_name:ident) => {
impl FromF64Approx for $ty {
fn from_f64_approx(v: f64) -> Option<Self> {
num_traits::ToPrimitive::$fn_name(&v)
}
}
};
}
impl_fromf64_approx!(u8, to_u8);
impl_fromf64_approx!(u16, to_u16);
impl_fromf64_approx!(u32, to_u32);
impl_fromf64_approx!(u64, to_u64);
impl_fromf64_approx!(i8, to_i8);
impl_fromf64_approx!(i16, to_i16);
impl_fromf64_approx!(i32, to_i32);
impl_fromf64_approx!(i64, to_i64);
impl_fromf64_approx!(f32, to_f32);
impl_fromf64_approx!(f64, to_f64);
pub struct InferredDenominator<N>(core::marker::PhantomData<N>);
impl<N> InferredDenominator<N> {
pub fn div_int<const D: u64>(numerator: N) -> DivInt<N, D> {
DivInt::from_numerator(numerator)
}
}