use crate::cast::CastFrom;
use crate::errors::{ParseIntError, TryFromCharError, TryFromIntError};
use crate::{Exponent, Int, Integer, Uint};
use core::str::FromStr;
pub trait IntegerConvertHelper {
const BITS: Exponent;
const SIGNED: bool;
fn leading_zeros_at_least_threshold(&self, threshold: Exponent) -> bool;
fn is_negative(&self) -> bool;
fn leading_ones_at_least_threshold(&self, threshold: Exponent) -> bool;
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> IntegerConvertHelper
for Integer<S, N, B, OM>
{
const BITS: Exponent = Self::BITS;
const SIGNED: bool = S;
#[inline]
fn leading_zeros_at_least_threshold(&self, threshold: Exponent) -> bool {
Self::leading_zeros_at_least_threshold(&self, threshold)
}
#[inline]
fn leading_ones_at_least_threshold(&self, threshold: Exponent) -> bool {
Self::leading_ones_at_least_threshold(&self, threshold)
}
#[inline]
fn is_negative(&self) -> bool {
self.is_negative_internal()
}
}
macro_rules! impl_int_convert_helper_for_primitive_int {
($($int: ty), *) => {
$(
impl IntegerConvertHelper for $int {
const BITS: Exponent = Self::BITS as Exponent;
#[allow(unused_comparisons)]
const SIGNED: bool = <$int>::MIN < 0;
#[inline]
fn leading_zeros_at_least_threshold(&self, threshold: Exponent) -> bool {
self.leading_zeros() >= threshold
}
#[inline]
fn leading_ones_at_least_threshold(&self, threshold: Exponent) -> bool {
self.leading_ones() >= threshold
}
#[inline]
fn is_negative(&self) -> bool {
#[allow(unused_comparisons)]
{ self < &0 }
}
}
)*
};
}
impl_int_convert_helper_for_primitive_int!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
);
#[inline]
fn uint_try_from_uint<U, V>(uint: U) -> Result<V, TryFromIntError>
where
V: CastFrom<U>,
U: IntegerConvertHelper,
V: IntegerConvertHelper,
{
if U::BITS <= V::BITS || uint.leading_zeros_at_least_threshold(U::BITS - V::BITS) {
Ok(V::cast_from(uint))
} else {
Err(TryFromIntError(()))
}
}
#[inline]
fn uint_try_from_int<I, U>(int: I) -> Result<U, TryFromIntError>
where
U: CastFrom<I>,
I: IntegerConvertHelper,
U: IntegerConvertHelper,
{
if int.is_negative() {
return Err(TryFromIntError(()));
}
if I::BITS - 1 <= U::BITS || int.leading_zeros_at_least_threshold(I::BITS - U::BITS) {
Ok(U::cast_from(int))
} else {
Err(TryFromIntError(()))
}
}
#[inline]
fn int_try_from_uint<U, I>(uint: U) -> Result<I, TryFromIntError>
where
I: CastFrom<U>,
U: IntegerConvertHelper,
I: IntegerConvertHelper,
{
if U::BITS <= I::BITS - 1 || uint.leading_zeros_at_least_threshold(U::BITS - I::BITS + 1) {
Ok(I::cast_from(uint))
} else {
Err(TryFromIntError(()))
}
}
#[inline]
fn int_try_from_int<I, J>(int: I) -> Result<J, TryFromIntError>
where
J: CastFrom<I>,
I: IntegerConvertHelper,
J: IntegerConvertHelper,
{
if I::BITS <= J::BITS {
return Ok(J::cast_from(int));
}
if int.is_negative() {
if int.leading_ones_at_least_threshold(I::BITS - J::BITS + 1) {
Ok(J::cast_from(int))
} else {
Err(TryFromIntError(()))
}
} else {
if int.leading_zeros_at_least_threshold(I::BITS - J::BITS + 1) {
Ok(J::cast_from(int))
} else {
Err(TryFromIntError(()))
}
}
}
#[inline]
fn integer_try_from_integer<I, J>(int: I) -> Result<J, TryFromIntError>
where
J: CastFrom<I>,
I: IntegerConvertHelper,
J: IntegerConvertHelper,
{
match (J::SIGNED, I::SIGNED) {
(false, false) => uint_try_from_uint(int),
(false, true) => uint_try_from_int(int),
(true, false) => int_try_from_uint(int),
(true, true) => int_try_from_int(int),
}
}
macro_rules! integer_try_from_into_primitive_integer {
($($uint: ty), *) => {
$(
impl<const S: bool, const N: usize, const B: usize, const OM: u8> TryFrom<Integer<S, N, B, OM>> for $uint {
type Error = TryFromIntError;
#[inline]
fn try_from(value: Integer<S, N, B, OM>) -> Result<Self, Self::Error> {
integer_try_from_integer(value)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> TryFrom<$uint> for Integer<S, N, B, OM> {
type Error = TryFromIntError;
#[inline]
fn try_from(value: $uint) -> Result<Self, Self::Error> {
integer_try_from_integer(value)
}
}
)*
}
}
integer_try_from_into_primitive_integer!(
u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
);
impl<
const S: bool,
const N: usize,
const B: usize,
const R: bool,
const M: usize,
const A: usize,
const OM: u8,
> TryFrom<&Integer<R, M, A, OM>> for Integer<S, N, B, OM>
{
type Error = TryFromIntError;
fn try_from(value: &Integer<R, M, A, OM>) -> Result<Self, Self::Error> {
integer_try_from_integer(*value)
}
}
impl<const N: usize, const B: usize, const M: usize, const A: usize, const OM: u8>
TryFrom<Int<N, B, OM>> for Uint<M, A, OM>
{
type Error = TryFromIntError;
fn try_from(value: Int<N, B, OM>) -> Result<Self, Self::Error> {
uint_try_from_int(value)
}
}
impl<const N: usize, const B: usize, const M: usize, const A: usize, const OM: u8>
TryFrom<Uint<N, B, OM>> for Int<M, A, OM>
{
type Error = TryFromIntError;
fn try_from(value: Uint<N, B, OM>) -> Result<Self, Self::Error> {
int_try_from_uint(value)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> From<bool>
for Integer<S, N, B, OM>
{
#[inline]
fn from(small: bool) -> Self {
Self::cast_from(small)
}
}
impl<const N: usize, const B: usize, const OM: u8> TryFrom<char> for Uint<N, B, OM> {
type Error = TryFromCharError;
#[inline]
fn try_from(c: char) -> Result<Self, Self::Error> {
<Self as TryFrom<u32>>::try_from(u32::from(c)).map_err(|_| TryFromCharError(()))
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> FromStr for Integer<S, N, B, OM> {
type Err = ParseIntError;
fn from_str(src: &str) -> Result<Self, Self::Err> {
Self::from_str_radix(src, 10)
}
}
#[cfg(test)]
mod tests {
use crate::test;
use crate::test::cast_types::*;
crate::test::test_all! {
testing unsigned;
test::test_tryfrom_same_sign!(utest; TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10);
test::test_from! {
function: <utest as TryFrom>::try_from,
from_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, char, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10) }
test::test_into! {
function: <utest as TryInto>::try_into,
into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10)
}
}
crate::test::test_all! {
testing signed;
test::test_tryfrom_same_sign!(itest; TestInt1, TestInt2, TestInt3, TestInt4, TestInt5, TestInt6, TestInt7, TestInt8, TestInt9, TestInt10);
test::test_from! {
function: <itest as TryFrom>::try_from,
from_types: (i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, bool, TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10)
}
test::test_into! {
function: <itest as TryInto>::try_into,
into_types: (u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, TestUint1, TestUint2, TestUint3, TestUint4, TestUint5, TestUint6, TestUint7, TestUint8, TestUint9, TestUint10)
}
}
}
#[cfg(test)]
mod double_custom_bit_width_convert_tests {
use crate::Integer;
use crate::test::BitInt;
use crate::literal_parse::get_size_params_from_bits;
macro_rules! test_double_custom_bit_width_convert {
($($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>::try_from(&v);
let b = Integer::<false, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::try_from(&w);
let w = Integer::from(v);
let c = BitInt::<true, $to>::try_from(&v);
let d = Integer::<true, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::try_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>::try_from(&v);
let b = Integer::<false, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::try_from(&w);
let w = Integer::from(v);
let c = BitInt::<true, $to>::try_from(&v);
let d = Integer::<true, {get_size_params_from_bits($to).0}, {get_size_params_from_bits($to).1}>::try_from(&w);
crate::test::test_eq(a, b) && crate::test::test_eq(c, d)
}
}
)*
}
};
}
test_double_custom_bit_width_convert!(
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,
128 => 127,
128 => 129,
129 => 128,
173 => 256,
256 => 173,
5 => 11,
4 => 23,
23 => 4,
289 => 160,
160 => 289
);
}