use crate::{
traits::FixedBits, FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16,
FixedU32, FixedU64, FixedU8,
};
use core::mem;
pub(crate) enum Shift {
Right(u32),
Left(u32),
RightAll,
LeftAll,
}
#[inline]
pub(crate) fn src_shift(dst_frac: i32, src_frac: i32, src_bits: u32) -> Shift {
if dst_frac <= src_frac {
let shift = src_frac.wrapping_sub(dst_frac) as u32;
if shift >= src_bits {
Shift::RightAll
} else {
Shift::Right(shift)
}
} else {
let shift = dst_frac.wrapping_sub(src_frac) as u32;
if shift >= src_bits {
Shift::LeftAll
} else {
Shift::Left(shift)
}
}
}
macro_rules! impl_fixed_from_bits {
($Fixed:ident($Inner:ident, $nbits:expr), $InnerI:ident, $InnerU:ident) => {
impl<const FRAC: i32> $Fixed<FRAC> {
pub(crate) fn fixed_from_bits<Src>(src: Src, src_frac: i32) -> ($Fixed<FRAC>, bool)
where
Src: FixedBits,
{
let src_neg_overflow = Src::overflowing_cast_from(-1i8).1;
let src_is_signed = !src_neg_overflow;
let src_bits = mem::size_of::<Src>() as u32 * 8;
if $nbits > src_bits && FRAC > src_frac {
if src_is_signed {
let (widened, overflow): ($InnerI, bool) = src.overflowing_cast();
debug_assert!(!overflow);
return $Fixed::fixed_from_bits(widened, src_frac);
}
let (widened, overflow): ($InnerU, bool) = src.overflowing_cast();
debug_assert!(!overflow);
return $Fixed::fixed_from_bits(widened, src_frac);
}
match src_shift(FRAC, src_frac, src_bits) {
Shift::Right(shift) => {
let shifted = src >> shift;
let (bits, overflow) = shifted.overflowing_cast();
($Fixed::from_bits(bits), overflow)
}
Shift::Left(shift) => {
let (cast, overflow1): ($Inner, bool) = src.overflowing_cast();
let shifted = cast << shift;
let overflow2 = (shifted >> shift) != cast;
($Fixed::from_bits(shifted), overflow1 || overflow2)
}
Shift::RightAll => {
if src_is_signed {
let shifted = src >> src_bits - 1;
let (bits, overflow) = shifted.overflowing_cast();
($Fixed::from_bits(bits), overflow)
} else {
($Fixed::ZERO, false)
}
}
Shift::LeftAll => {
let src_zero = Src::overflowing_cast_from(0u8).0;
($Fixed::ZERO, src != src_zero)
}
}
}
}
};
}
impl_fixed_from_bits! { FixedI8(i8, 8), i8, u8 }
impl_fixed_from_bits! { FixedI16(i16, 16), i16, u16 }
impl_fixed_from_bits! { FixedI32(i32, 32), i32, u32 }
impl_fixed_from_bits! { FixedI64(i64, 64), i64, u64 }
impl_fixed_from_bits! { FixedI128(i128, 128), i128, u128 }
impl_fixed_from_bits! { FixedU8(u8, 8), i8, u8 }
impl_fixed_from_bits! { FixedU16(u16, 16), i16, u16 }
impl_fixed_from_bits! { FixedU32(u32, 32), i32, u32 }
impl_fixed_from_bits! { FixedU64(u64, 64), i64, u64 }
impl_fixed_from_bits! { FixedU128(u128, 128), i128, u128 }