Skip to content

Commit c076bb8

Browse files
bors[bot]milesandcuviper
authored
Merge #123
123: Add TryFrom impls r=cuviper a=milesand Closes #120 Currently contains: * `TryFrom` translations of existing conversion traits. * A minimal Error type used for all `TryFrom` implementations. Additional implemetations (e.g. `TryFrom<BigInt> for BigUint` which skips `clone()`) could be beneficial. Also, no new tests have been added since all new impls are basically thin adapters around existing, tested methods. It may be beneficial to add them regardless. Co-authored-by: Jewoo Lee <[email protected]> Co-authored-by: Josh Stone <[email protected]>
2 parents 75c3e07 + 029d04d commit c076bb8

File tree

5 files changed

+179
-2
lines changed

5 files changed

+179
-2
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ sudo: false
33
rust:
44
- 1.31.0 # 2018!
55
- 1.32.0 # rand
6-
- 1.34.0 # quickcheck
6+
- 1.34.0 # quickcheck, has_try_from
77
- 1.36.0 # alloc
88
- stable
99
- beta

build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ fn main() {
99
if pointer_width.as_ref().map(String::as_str) == Ok("64") {
1010
autocfg::emit("u64_digit");
1111
}
12+
let ac = autocfg::new();
13+
if ac.probe_path("std::convert::TryFrom") || ac.probe_path("core::convert::TryFrom") {
14+
autocfg::emit("has_try_from");
15+
}
1216

1317
autocfg::rerun_path("build.rs");
1418

src/bigint.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
use crate::std_alloc::Box;
66
use crate::std_alloc::{String, Vec};
77
use core::cmp::Ordering::{self, Equal, Greater, Less};
8+
#[cfg(has_try_from)]
9+
use core::convert::TryFrom;
810
use core::default::Default;
911
use core::fmt;
1012
use core::hash;
@@ -29,11 +31,13 @@ use num_traits::{
2931

3032
use self::Sign::{Minus, NoSign, Plus};
3133

32-
use super::ParseBigIntError;
3334
use crate::big_digit::{self, BigDigit, DoubleBigDigit};
3435
use crate::biguint;
3536
use crate::biguint::to_str_radix_reversed;
3637
use crate::biguint::{BigUint, IntDigits};
38+
use crate::ParseBigIntError;
39+
#[cfg(has_try_from)]
40+
use crate::TryFromBigIntError;
3741

3842
use crate::IsizePromotion;
3943
use crate::UsizePromotion;
@@ -2442,6 +2446,44 @@ impl ToPrimitive for BigInt {
24422446
}
24432447
}
24442448

2449+
macro_rules! impl_try_from_bigint {
2450+
($T:ty, $to_ty:path) => {
2451+
#[cfg(has_try_from)]
2452+
impl TryFrom<&BigInt> for $T {
2453+
type Error = TryFromBigIntError<()>;
2454+
2455+
#[inline]
2456+
fn try_from(value: &BigInt) -> Result<$T, TryFromBigIntError<()>> {
2457+
$to_ty(value).ok_or(TryFromBigIntError::new(()))
2458+
}
2459+
}
2460+
2461+
#[cfg(has_try_from)]
2462+
impl TryFrom<BigInt> for $T {
2463+
type Error = TryFromBigIntError<BigInt>;
2464+
2465+
#[inline]
2466+
fn try_from(value: BigInt) -> Result<$T, TryFromBigIntError<BigInt>> {
2467+
<$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
2468+
}
2469+
}
2470+
};
2471+
}
2472+
2473+
impl_try_from_bigint!(u8, ToPrimitive::to_u8);
2474+
impl_try_from_bigint!(u16, ToPrimitive::to_u16);
2475+
impl_try_from_bigint!(u32, ToPrimitive::to_u32);
2476+
impl_try_from_bigint!(u64, ToPrimitive::to_u64);
2477+
impl_try_from_bigint!(usize, ToPrimitive::to_usize);
2478+
impl_try_from_bigint!(u128, ToPrimitive::to_u128);
2479+
2480+
impl_try_from_bigint!(i8, ToPrimitive::to_i8);
2481+
impl_try_from_bigint!(i16, ToPrimitive::to_i16);
2482+
impl_try_from_bigint!(i32, ToPrimitive::to_i32);
2483+
impl_try_from_bigint!(i64, ToPrimitive::to_i64);
2484+
impl_try_from_bigint!(isize, ToPrimitive::to_isize);
2485+
impl_try_from_bigint!(i128, ToPrimitive::to_i128);
2486+
24452487
impl FromPrimitive for BigInt {
24462488
#[inline]
24472489
fn from_i64(n: i64) -> Option<BigInt> {
@@ -2667,6 +2709,30 @@ impl biguint::ToBigUint for BigInt {
26672709
}
26682710
}
26692711

2712+
#[cfg(has_try_from)]
2713+
impl TryFrom<&BigInt> for BigUint {
2714+
type Error = TryFromBigIntError<()>;
2715+
2716+
#[inline]
2717+
fn try_from(value: &BigInt) -> Result<BigUint, TryFromBigIntError<()>> {
2718+
value.to_biguint().ok_or(TryFromBigIntError::new(()))
2719+
}
2720+
}
2721+
2722+
#[cfg(has_try_from)]
2723+
impl TryFrom<BigInt> for BigUint {
2724+
type Error = TryFromBigIntError<BigInt>;
2725+
2726+
#[inline]
2727+
fn try_from(value: BigInt) -> Result<BigUint, TryFromBigIntError<BigInt>> {
2728+
if value.sign() == Sign::Minus {
2729+
Err(TryFromBigIntError::new(value))
2730+
} else {
2731+
Ok(value.data)
2732+
}
2733+
}
2734+
}
2735+
26702736
macro_rules! impl_to_bigint {
26712737
($T:ty, $from_ty:path) => {
26722738
impl ToBigInt for $T {

src/biguint.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use crate::std_alloc::Box;
33
use crate::std_alloc::{Cow, String, Vec};
44
use core::cmp;
55
use core::cmp::Ordering::{self, Equal, Greater, Less};
6+
#[cfg(has_try_from)]
7+
use core::convert::TryFrom;
68
use core::default::Default;
79
use core::fmt;
810
use core::hash;
@@ -43,6 +45,8 @@ use self::monty::monty_modpow;
4345
use crate::UsizePromotion;
4446

4547
use crate::ParseBigIntError;
48+
#[cfg(has_try_from)]
49+
use crate::TryFromBigIntError;
4650

4751
#[cfg(feature = "quickcheck")]
4852
use quickcheck::{Arbitrary, Gen};
@@ -1929,6 +1933,44 @@ impl ToPrimitive for BigUint {
19291933
}
19301934
}
19311935

1936+
macro_rules! impl_try_from_biguint {
1937+
($T:ty, $to_ty:path) => {
1938+
#[cfg(has_try_from)]
1939+
impl TryFrom<&BigUint> for $T {
1940+
type Error = TryFromBigIntError<()>;
1941+
1942+
#[inline]
1943+
fn try_from(value: &BigUint) -> Result<$T, TryFromBigIntError<()>> {
1944+
$to_ty(value).ok_or(TryFromBigIntError::new(()))
1945+
}
1946+
}
1947+
1948+
#[cfg(has_try_from)]
1949+
impl TryFrom<BigUint> for $T {
1950+
type Error = TryFromBigIntError<BigUint>;
1951+
1952+
#[inline]
1953+
fn try_from(value: BigUint) -> Result<$T, TryFromBigIntError<BigUint>> {
1954+
<$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
1955+
}
1956+
}
1957+
};
1958+
}
1959+
1960+
impl_try_from_biguint!(u8, ToPrimitive::to_u8);
1961+
impl_try_from_biguint!(u16, ToPrimitive::to_u16);
1962+
impl_try_from_biguint!(u32, ToPrimitive::to_u32);
1963+
impl_try_from_biguint!(u64, ToPrimitive::to_u64);
1964+
impl_try_from_biguint!(usize, ToPrimitive::to_usize);
1965+
impl_try_from_biguint!(u128, ToPrimitive::to_u128);
1966+
1967+
impl_try_from_biguint!(i8, ToPrimitive::to_i8);
1968+
impl_try_from_biguint!(i16, ToPrimitive::to_i16);
1969+
impl_try_from_biguint!(i32, ToPrimitive::to_i32);
1970+
impl_try_from_biguint!(i64, ToPrimitive::to_i64);
1971+
impl_try_from_biguint!(isize, ToPrimitive::to_isize);
1972+
impl_try_from_biguint!(i128, ToPrimitive::to_i128);
1973+
19321974
impl FromPrimitive for BigUint {
19331975
#[inline]
19341976
fn from_i64(n: i64) -> Option<BigUint> {
@@ -2034,6 +2076,27 @@ impl_biguint_from_uint!(u16);
20342076
impl_biguint_from_uint!(u32);
20352077
impl_biguint_from_uint!(usize);
20362078

2079+
macro_rules! impl_biguint_try_from_int {
2080+
($T:ty, $from_ty:path) => {
2081+
#[cfg(has_try_from)]
2082+
impl TryFrom<$T> for BigUint {
2083+
type Error = TryFromBigIntError<()>;
2084+
2085+
#[inline]
2086+
fn try_from(value: $T) -> Result<BigUint, TryFromBigIntError<()>> {
2087+
$from_ty(value).ok_or(TryFromBigIntError::new(()))
2088+
}
2089+
}
2090+
};
2091+
}
2092+
2093+
impl_biguint_try_from_int!(i8, FromPrimitive::from_i8);
2094+
impl_biguint_try_from_int!(i16, FromPrimitive::from_i16);
2095+
impl_biguint_try_from_int!(i32, FromPrimitive::from_i32);
2096+
impl_biguint_try_from_int!(i64, FromPrimitive::from_i64);
2097+
impl_biguint_try_from_int!(isize, FromPrimitive::from_isize);
2098+
impl_biguint_try_from_int!(i128, FromPrimitive::from_i128);
2099+
20372100
/// A generic trait for converting a value to a `BigUint`.
20382101
pub trait ToBigUint {
20392102
/// Converts the value of `self` to a `BigUint`.

src/lib.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,50 @@ impl Error for ParseBigIntError {
182182
}
183183
}
184184

185+
/// The error type returned when a checked conversion regarding big integer fails.
186+
#[cfg(has_try_from)]
187+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
188+
pub struct TryFromBigIntError<T> {
189+
original: T,
190+
}
191+
192+
#[cfg(has_try_from)]
193+
impl<T> TryFromBigIntError<T> {
194+
fn new(original: T) -> Self {
195+
TryFromBigIntError { original }
196+
}
197+
198+
fn __description(&self) -> &str {
199+
"out of range conversion regarding big integer attempted"
200+
}
201+
202+
/// Extract the original value, if available. The value will be available
203+
/// if the type before conversion was either [`BigInt`] or [`BigUint`].
204+
///
205+
/// [`BigInt`]: struct.BigInt.html
206+
/// [`BigUint`]: struct.BigUint.html
207+
pub fn into_original(self) -> T {
208+
self.original
209+
}
210+
}
211+
212+
#[cfg(all(feature = "std", has_try_from))]
213+
impl<T> std::error::Error for TryFromBigIntError<T>
214+
where
215+
T: fmt::Debug,
216+
{
217+
fn description(&self) -> &str {
218+
self.__description()
219+
}
220+
}
221+
222+
#[cfg(has_try_from)]
223+
impl<T> fmt::Display for TryFromBigIntError<T> {
224+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225+
self.__description().fmt(f)
226+
}
227+
}
228+
185229
pub use crate::biguint::BigUint;
186230
pub use crate::biguint::ToBigUint;
187231

0 commit comments

Comments
 (0)