Skip to content

Commit d9aa235

Browse files
committed
Merge impl_* file refactorings into trunk
2 parents c274173 + 50ec8e4 commit d9aa235

File tree

5 files changed

+679
-424
lines changed

5 files changed

+679
-424
lines changed

src/impl_convert.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//! Code for implementing From/To BigDecimals
2+
3+
use crate::BigDecimal;
4+
use crate::stdlib::convert::TryFrom;
5+
6+
use num_bigint::BigInt;
7+
8+
9+
macro_rules! impl_from_int_primitive {
10+
($t:ty) => {
11+
impl From<$t> for BigDecimal {
12+
fn from(n: $t) -> Self {
13+
BigDecimal {
14+
int_val: n.into(),
15+
scale: 0,
16+
}
17+
}
18+
}
19+
20+
impl From<&$t> for BigDecimal {
21+
fn from(n: &$t) -> Self {
22+
BigDecimal {
23+
int_val: (*n).into(),
24+
scale: 0,
25+
}
26+
}
27+
}
28+
};
29+
}
30+
31+
impl_from_int_primitive!(u8);
32+
impl_from_int_primitive!(u16);
33+
impl_from_int_primitive!(u32);
34+
impl_from_int_primitive!(u64);
35+
impl_from_int_primitive!(u128);
36+
impl_from_int_primitive!(i8);
37+
impl_from_int_primitive!(i16);
38+
impl_from_int_primitive!(i32);
39+
impl_from_int_primitive!(i64);
40+
impl_from_int_primitive!(i128);
41+
42+
43+
impl TryFrom<f32> for BigDecimal {
44+
type Error = super::ParseBigDecimalError;
45+
46+
#[inline]
47+
fn try_from(n: f32) -> Result<Self, Self::Error> {
48+
crate::parsing::try_parse_from_f32(n)
49+
}
50+
}
51+
52+
impl TryFrom<f64> for BigDecimal {
53+
type Error = super::ParseBigDecimalError;
54+
55+
#[inline]
56+
fn try_from(n: f64) -> Result<Self, Self::Error> {
57+
crate::parsing::try_parse_from_f64(n)
58+
}
59+
}
60+
61+
62+
impl From<BigInt> for BigDecimal {
63+
fn from(int_val: BigInt) -> Self {
64+
BigDecimal {
65+
int_val: int_val,
66+
scale: 0,
67+
}
68+
}
69+
}
70+
71+
// Anything that may be a big-integer paired with a scale
72+
// parameter may be a bigdecimal
73+
impl<T: Into<BigInt>> From<(T, i64)> for BigDecimal {
74+
fn from((int_val, scale): (T, i64)) -> Self {
75+
Self {
76+
int_val: int_val.into(),
77+
scale: scale,
78+
}
79+
}
80+
}

src/impl_num.rs

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
//! Code for num_traits
2+
3+
use num_traits::{Num, FromPrimitive, ToPrimitive, AsPrimitive};
4+
use num_bigint::{BigInt, Sign, ToBigInt};
5+
6+
use stdlib::str::FromStr;
7+
use stdlib::string::{String, ToString};
8+
use stdlib::convert::TryFrom;
9+
use stdlib::ops::Neg;
10+
11+
use crate::BigDecimal;
12+
use crate::ParseBigDecimalError;
13+
14+
#[cfg(not(feature = "std"))]
15+
// f64::powi is only available in std, no_std must use libm
16+
fn powi(x: f64, n: f64) -> f64 {
17+
libm::pow(x, n)
18+
}
19+
20+
#[cfg(feature = "std")]
21+
fn powi(x: f64, n: i32) -> f64 {
22+
x.powi(n)
23+
}
24+
25+
impl Num for BigDecimal {
26+
type FromStrRadixErr = ParseBigDecimalError;
27+
28+
/// Creates and initializes a BigDecimal.
29+
#[inline]
30+
fn from_str_radix(s: &str, radix: u32) -> Result<BigDecimal, ParseBigDecimalError> {
31+
if radix != 10 {
32+
return Err(ParseBigDecimalError::Other(String::from(
33+
"The radix for decimal MUST be 10",
34+
)));
35+
}
36+
37+
let exp_separator: &[_] = &['e', 'E'];
38+
39+
// split slice into base and exponent parts
40+
let (base_part, exponent_value) = match s.find(exp_separator) {
41+
// exponent defaults to 0 if (e|E) not found
42+
None => (s, 0),
43+
44+
// split and parse exponent field
45+
Some(loc) => {
46+
// slice up to `loc` and 1 after to skip the 'e' char
47+
let (base, exp) = (&s[..loc], &s[loc + 1..]);
48+
49+
// special consideration for rust 1.0.0 which would not
50+
// parse a leading '+'
51+
let exp = match exp.chars().next() {
52+
Some('+') => &exp[1..],
53+
_ => exp,
54+
};
55+
56+
(base, i64::from_str(exp)?)
57+
}
58+
};
59+
60+
// TEMPORARY: Test for emptiness - remove once BigInt supports similar error
61+
if base_part.is_empty() {
62+
return Err(ParseBigDecimalError::Empty);
63+
}
64+
65+
// split decimal into a digit string and decimal-point offset
66+
let (digits, decimal_offset): (String, _) = match base_part.find('.') {
67+
// No dot! pass directly to BigInt
68+
None => (base_part.to_string(), 0),
69+
70+
// decimal point found - necessary copy into new string buffer
71+
Some(loc) => {
72+
// split into leading and trailing digits
73+
let (lead, trail) = (&base_part[..loc], &base_part[loc + 1..]);
74+
75+
// copy all leading characters into 'digits' string
76+
let mut digits = String::from(lead);
77+
78+
// copy all trailing characters after '.' into the digits string
79+
digits.push_str(trail);
80+
81+
// count number of trailing digits
82+
let trail_digits = trail.chars().filter(|c| *c != '_').count();
83+
84+
(digits, trail_digits as i64)
85+
}
86+
};
87+
88+
let scale = decimal_offset - exponent_value;
89+
let big_int = BigInt::from_str_radix(&digits, radix)?;
90+
91+
Ok(BigDecimal::new(big_int, scale))
92+
}
93+
}
94+
95+
impl ToPrimitive for BigDecimal {
96+
fn to_i64(&self) -> Option<i64> {
97+
match self.sign() {
98+
Sign::Minus | Sign::Plus => self.with_scale(0).int_val.to_i64(),
99+
Sign::NoSign => Some(0),
100+
}
101+
}
102+
fn to_i128(&self) -> Option<i128> {
103+
match self.sign() {
104+
Sign::Minus | Sign::Plus => self.with_scale(0).int_val.to_i128(),
105+
Sign::NoSign => Some(0),
106+
}
107+
}
108+
fn to_u64(&self) -> Option<u64> {
109+
match self.sign() {
110+
Sign::Plus => self.with_scale(0).int_val.to_u64(),
111+
Sign::NoSign => Some(0),
112+
Sign::Minus => None,
113+
}
114+
}
115+
fn to_u128(&self) -> Option<u128> {
116+
match self.sign() {
117+
Sign::Plus => self.with_scale(0).int_val.to_u128(),
118+
Sign::NoSign => Some(0),
119+
Sign::Minus => None,
120+
}
121+
}
122+
123+
fn to_f64(&self) -> Option<f64> {
124+
self.int_val.to_f64().map(|x| x * powi(10f64, self.scale.neg().as_()))
125+
}
126+
}
127+
128+
129+
impl FromPrimitive for BigDecimal {
130+
#[inline]
131+
fn from_i64(n: i64) -> Option<Self> {
132+
Some(BigDecimal::from(n))
133+
}
134+
135+
#[inline]
136+
fn from_u64(n: u64) -> Option<Self> {
137+
Some(BigDecimal::from(n))
138+
}
139+
140+
#[inline]
141+
fn from_i128(n: i128) -> Option<Self> {
142+
Some(BigDecimal::from(n))
143+
}
144+
145+
#[inline]
146+
fn from_u128(n: u128) -> Option<Self> {
147+
Some(BigDecimal::from(n))
148+
}
149+
150+
#[inline]
151+
fn from_f32(n: f32) -> Option<Self> {
152+
BigDecimal::try_from(n).ok()
153+
}
154+
155+
#[inline]
156+
fn from_f64(n: f64) -> Option<Self> {
157+
BigDecimal::try_from(n).ok()
158+
}
159+
}
160+
161+
impl ToBigInt for BigDecimal {
162+
fn to_bigint(&self) -> Option<BigInt> {
163+
Some(self.with_scale(0).int_val)
164+
}
165+
}

0 commit comments

Comments
 (0)