use crate::{DigestWriter, Digestible};
use byteorder::ByteOrder;
#[doc(hidden)]
pub trait FloatType {
type TargetInt: Digestible;
fn ceil(self) -> Self::TargetInt;
fn floor(self) -> Self::TargetInt;
fn round(self) -> Self::TargetInt;
}
macro_rules! de_ref_then_call_inner {
(deref: $T:path) => {
type TargetInt = <$T>::TargetInt;
#[inline(always)]
fn ceil(self) -> Self::TargetInt {
(*self).ceil()
}
#[inline(always)]
fn floor(self) -> Self::TargetInt {
(*self).floor()
}
#[inline(always)]
fn round(self) -> Self::TargetInt {
(*self).round()
}
};
($tyToImpl:ident) =>{
impl<T: FloatType + Copy> FloatType for $tyToImpl<T>{
de_ref_then_call_inner!(deref: T);
}
};
}
impl<'a, F: FloatType + Copy> FloatType for &'a F {
de_ref_then_call_inner!(deref: F);
}
impl<'a, T: FloatType + Copy> FloatType for &'a Option<T> {
type TargetInt = Option<T::TargetInt>;
#[inline(always)]
fn ceil(self) -> Self::TargetInt {
self.as_ref().map(|v| v.ceil())
}
#[inline(always)]
fn floor(self) -> Self::TargetInt {
self.as_ref().map(|v| v.floor())
}
#[inline(always)]
fn round(self) -> Self::TargetInt {
self.as_ref().map(|v| v.round())
}
}
#[cfg(feature = "alloc")]
mod has_alloc {
use crate::digest_with::floats::FloatType;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::sync::Arc;
de_ref_then_call_inner!(Arc);
de_ref_then_call_inner!(Rc);
de_ref_then_call_inner!(Box);
}
macro_rules! impl_float_type {
($float:ty, $target:ty) => {
impl FloatType for $float {
type TargetInt = $target;
#[inline(always)]
fn ceil(self) -> Self::TargetInt {
self.ceil() as $target
}
#[inline(always)]
fn floor(self) -> Self::TargetInt {
self.floor() as $target
}
#[inline(always)]
fn round(self) -> Self::TargetInt {
self.round() as $target
}
}
};
}
impl_float_type!(f32, i32);
impl_float_type!(f64, i64);
#[inline(always)]
pub fn digest_ceil<B: ByteOrder, W: DigestWriter>(bytes: impl FloatType, writer: &mut W) {
bytes.ceil().digest::<B, W>(writer)
}
#[inline(always)]
pub fn digest_floor<B: ByteOrder, W: DigestWriter>(bytes: impl FloatType, writer: &mut W) {
bytes.floor().digest::<B, W>(writer)
}
#[inline(always)]
pub fn digest_round<B: ByteOrder, W: DigestWriter>(bytes: impl FloatType, writer: &mut W) {
bytes.round().digest::<B, W>(writer)
}