use super::{Integer, Uint};
use crate::cast;
#[inline]
const fn bytes_cast<const N: usize, const M: usize, const SIGNED: bool>(from: [u8; N]) -> [u8; M] {
let pad = if SIGNED && M > N && (from[N - 1] as i8).is_negative() {
u8::MAX
} else {
0
};
let mut bytes = [pad; M];
let mut i = 0;
while i < if N < M { N } else { M } {
bytes[i] = from[i];
i += 1;
}
bytes
}
macro_rules! cast_uint_from_to_prim_int {
($($int: ty), *) => {
$(
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CastFrom<Integer<S, N, B, OM>> for $int {
#[inline]
fn cast_from(value: Integer<S, N, B, OM>) -> Self {
const BYTES: usize = (<$int>::BITS as usize) / 8;
let bytes = bytes_cast::<N, BYTES, S>(value.to_bytes());
Self::from_le_bytes(bytes)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CastFrom<$int> for Integer<S, N, B, OM> {
#[inline]
fn cast_from(value: $int) -> Self {
#[allow(unused_comparisons)]
const SIGNED: bool = <$int>::MIN < 0;
const BYTES: usize = (<$int>::BITS as usize) / 8;
let bytes = bytes_cast::<BYTES, N, SIGNED>(value.to_le_bytes());
let mut out = Self::from_bytes(bytes);
out.set_sign_bits();
out
}
}
)*
};
}
macro_rules! cast_int_from_float {
($value: ident) => {
if $value.is_sign_negative() {
let u = Uint::cast_from(-$value);
if u >= crate::Int::MIN.cast_unsigned() {
Self::MIN
} else {
(-(u.force_sign::<true>())).force_sign()
}
} else {
let u = Uint::cast_from($value);
let i = u.cast_signed();
if i.is_negative() {
Self::MAX
} else {
i.force_sign()
}
}
};
}
pub(crate) use cast_int_from_float;
macro_rules! cast_uint_from_to_prim_float {
($($f: ty), *) => {
$(
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CastFrom<Integer<S, N, B, OM>> for $f {
#[inline]
fn cast_from(value: Integer<S, N, B, OM>) -> Self {
if !S {
cast::float::cast_float_from_uint(value.force_sign::<false>())
} else {
let f = <$f>::cast_from(value.unsigned_abs_internal());
if value.is_negative_internal() { -f } else { f }
}
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CastFrom<$f> for Integer<S, N, B, OM> {
#[inline]
fn cast_from(value: $f) -> Self {
if !S {
cast::float::cast_uint_from_float::<$f, Uint<N, B, OM>>(value).force_sign::<S>()
} else {
crate::integer::cast::cast_int_from_float!(value)
}
}
}
)*
};
}
use crate::Exponent;
use crate::cast::CastFrom;
#[allow(unused_imports)]
use crate::cast::float::{CastFloatFromUintHelper, CastUintFromFloatHelper, FloatMantissa};
impl<const N: usize, const B: usize, const OM: u8> CastUintFromFloatHelper for Uint<N, B, OM> {
const MAX: Self = Self::MAX;
const MIN: Self = Self::MIN;
}
impl<const N: usize, const B: usize, const OM: u8> CastFloatFromUintHelper for Uint<N, B, OM> {
fn trailing_zeros(self) -> Exponent {
Self::trailing_zeros(self)
}
}
cast_uint_from_to_prim_int!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
);
cast_uint_from_to_prim_float!(f32, f64);
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CastFrom<bool>
for Integer<S, N, B, OM>
{
#[inline]
fn cast_from(value: bool) -> Self {
if value { Self::ONE } else { Self::ZERO }
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> CastFrom<char>
for Integer<S, N, B, OM>
{
#[inline]
fn cast_from(value: char) -> Self {
Self::cast_from(value as u32)
}
}
impl<
const S: bool,
const N: usize,
const B: usize,
const R: bool,
const M: usize,
const A: usize,
const OM: u8,
> CastFrom<Integer<R, M, A, OM>> for Integer<S, N, B, OM>
{
#[inline]
fn cast_from(value: Integer<R, M, A, OM>) -> Self {
let bytes = bytes_cast::<M, N, R>(value.to_bytes());
let mut out = Self::from_bytes(bytes);
out.set_sign_bits();
out
}
}
#[cfg(test)]
mod tests {
use crate::cast::{CastFrom, CastTo};
use crate::test;
use crate::test::cast_types::*;
crate::test::test_all! {
testing integers;
test::test_from! {
function: <stest as CastFrom>::cast_from,
from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, bool, char, TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10)
}
test::test_into! {
function: <stest as CastTo>::cast_to,
into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64, TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10)
}
}
}
#[cfg(test)]
crate::test::test_all_custom_bit_widths! {
use crate::cast::{CastFrom, CastTo};
use crate::test;
test::test_from! {
function: <utest as CastFrom>::cast_from,
from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize)
}
test::test_into! {
function: <utest as CastTo>::cast_to,
into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize)
}
test::test_from! {
function: <itest as CastFrom>::cast_from,
from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize)
}
test::test_into! {
function: <itest as CastTo>::cast_to,
into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize)
}
}
#[cfg(test)]
mod double_custom_bit_width_cast_tests {
use crate::test::BitInt;
use crate::cast::CastFrom;
use crate::Integer;
use crate::literal_parse::get_size_params_from_bits;
macro_rules! test_double_custom_bit_width_cast {
($($from: literal => $to: literal), *) => {
paste::paste! {
$(
quickcheck::quickcheck! {
fn [<quickcheck_cast_from_u_ $from _to $to _bits>](v: BitInt<false, $from>) -> bool {
let w = Integer::from(v);
let a = BitInt::<false, $to>::cast_from(v);
let b = Integer::<false, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::cast_from(w);
let w = Integer::from(v);
let c = BitInt::<true, $to>::cast_from(v);
let d = Integer::<true, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::cast_from(w);
crate::test::test_eq(a, b) && crate::test::test_eq(c, d)
}
fn [<quickcheck_cast_from_i_ $from _to $to _bits>](v: BitInt<true, $from>) -> bool {
let w = Integer::from(v);
let a = BitInt::<false, $to>::cast_from(v);
let b = Integer::<false, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::cast_from(w);
let w = Integer::from(v);
let c = BitInt::<true, $to>::cast_from(v);
let d = Integer::<true, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::cast_from(w);
crate::test::test_eq(a, b) && crate::test::test_eq(c, d)
}
}
)*
}
};
}
test_double_custom_bit_width_cast!(
8 => 16,
16 => 32,
32 => 64,
64 => 128,
16 => 8,
32 => 16,
64 => 32,
128 => 64,
16 => 128,
8 => 64,
128 => 32,
64 => 16,
127 => 128,
129 => 128,
173 => 256,
256 => 173,
5 => 11,
4 => 23,
23 => 4,
289 => 160,
160 => 289
);
}