simplify from_str and start adding support for 2, 8, 16 radixes
This commit is contained in:
parent
e6f64a44b2
commit
852040e876
401
src/from_str.rs
401
src/from_str.rs
|
@ -28,7 +28,7 @@ use core::{
|
||||||
|
|
||||||
// 5^3 × 2 < 2^8 => (10^3 - 1) × 2^(8-3+1) < 2^16
|
// 5^3 × 2 < 2^8 => (10^3 - 1) × 2^(8-3+1) < 2^16
|
||||||
// Returns None for large fractions that are rounded to 1.0
|
// Returns None for large fractions that are rounded to 1.0
|
||||||
pub fn dec3_to_bin8(a: u16, dump_bits: u32) -> Option<u8> {
|
fn dec3_to_bin8(a: u16, dump_bits: u32) -> Option<u8> {
|
||||||
debug_assert!(a < 10u16.pow(3));
|
debug_assert!(a < 10u16.pow(3));
|
||||||
debug_assert!(dump_bits <= 8);
|
debug_assert!(dump_bits <= 8);
|
||||||
let divisor = 5u16.pow(3) * 2;
|
let divisor = 5u16.pow(3) * 2;
|
||||||
|
@ -42,7 +42,7 @@ pub fn dec3_to_bin8(a: u16, dump_bits: u32) -> Option<u8> {
|
||||||
}
|
}
|
||||||
// 5^6 × 2 < 2^16 => (10^6 - 1) × 2^(16-6+1) < 2^32
|
// 5^6 × 2 < 2^16 => (10^6 - 1) × 2^(16-6+1) < 2^32
|
||||||
// Returns None for large fractions that are rounded to 1.0
|
// Returns None for large fractions that are rounded to 1.0
|
||||||
pub fn dec6_to_bin16(a: u32, dump_bits: u32) -> Option<u16> {
|
fn dec6_to_bin16(a: u32, dump_bits: u32) -> Option<u16> {
|
||||||
debug_assert!(a < 10u32.pow(6));
|
debug_assert!(a < 10u32.pow(6));
|
||||||
debug_assert!(dump_bits <= 16);
|
debug_assert!(dump_bits <= 16);
|
||||||
let divisor = 5u32.pow(6) * 2;
|
let divisor = 5u32.pow(6) * 2;
|
||||||
|
@ -56,7 +56,7 @@ pub fn dec6_to_bin16(a: u32, dump_bits: u32) -> Option<u16> {
|
||||||
}
|
}
|
||||||
// 5^13 × 2 < 2^32 => (10^13 - 1) × 2^(32-13+1) < 2^64
|
// 5^13 × 2 < 2^32 => (10^13 - 1) × 2^(32-13+1) < 2^64
|
||||||
// Returns None for large fractions that are rounded to 1.0
|
// Returns None for large fractions that are rounded to 1.0
|
||||||
pub fn dec13_to_bin32(a: u64, dump_bits: u32) -> Option<u32> {
|
fn dec13_to_bin32(a: u64, dump_bits: u32) -> Option<u32> {
|
||||||
debug_assert!(a < 10u64.pow(13));
|
debug_assert!(a < 10u64.pow(13));
|
||||||
debug_assert!(dump_bits <= 32);
|
debug_assert!(dump_bits <= 32);
|
||||||
let divisor = 5u64.pow(13) * 2;
|
let divisor = 5u64.pow(13) * 2;
|
||||||
|
@ -70,7 +70,7 @@ pub fn dec13_to_bin32(a: u64, dump_bits: u32) -> Option<u32> {
|
||||||
}
|
}
|
||||||
// 5^27 × 2 < 2^64 => (10^27 - 1) × 2^(64-27+1) < 2^128
|
// 5^27 × 2 < 2^64 => (10^27 - 1) × 2^(64-27+1) < 2^128
|
||||||
// Returns None for large fractions that are rounded to 1.0
|
// Returns None for large fractions that are rounded to 1.0
|
||||||
pub fn dec27_to_bin64(a: u128, dump_bits: u32) -> Option<u64> {
|
fn dec27_to_bin64(a: u128, dump_bits: u32) -> Option<u64> {
|
||||||
debug_assert!(a < 10u128.pow(27));
|
debug_assert!(a < 10u128.pow(27));
|
||||||
debug_assert!(dump_bits <= 64);
|
debug_assert!(dump_bits <= 64);
|
||||||
let divisor = 5u128.pow(27) * 2;
|
let divisor = 5u128.pow(27) * 2;
|
||||||
|
@ -84,7 +84,7 @@ pub fn dec27_to_bin64(a: u128, dump_bits: u32) -> Option<u64> {
|
||||||
}
|
}
|
||||||
// 5^54 × 2 < 2^128 => (10^54 - 1) × 2^(128-54+1) < 2^256
|
// 5^54 × 2 < 2^128 => (10^54 - 1) × 2^(128-54+1) < 2^256
|
||||||
// Returns None for large fractions that are rounded to 1.0
|
// Returns None for large fractions that are rounded to 1.0
|
||||||
pub fn dec27_27_to_bin128(hi: u128, lo: u128, dump_bits: u32) -> Option<u128> {
|
fn dec27_27_to_bin128(hi: u128, lo: u128, dump_bits: u32) -> Option<u128> {
|
||||||
debug_assert!(hi < 10u128.pow(27));
|
debug_assert!(hi < 10u128.pow(27));
|
||||||
debug_assert!(lo < 10u128.pow(27));
|
debug_assert!(lo < 10u128.pow(27));
|
||||||
debug_assert!(dump_bits <= 128);
|
debug_assert!(dump_bits <= 128);
|
||||||
|
@ -210,7 +210,7 @@ impl Display for ParseFixedError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(s: &str, can_be_neg: bool) -> Result<Parse<'_>, ParseFixedError> {
|
fn parse(s: &str, can_be_neg: bool, radix: i32) -> Result<Parse<'_>, ParseFixedError> {
|
||||||
let mut int = (0, 0);
|
let mut int = (0, 0);
|
||||||
let mut frac = (0, 0);
|
let mut frac = (0, 0);
|
||||||
let mut has_sign = false;
|
let mut has_sign = false;
|
||||||
|
@ -218,20 +218,20 @@ fn parse(s: &str, can_be_neg: bool) -> Result<Parse<'_>, ParseFixedError> {
|
||||||
let mut has_digits = false;
|
let mut has_digits = false;
|
||||||
let mut has_point = false;
|
let mut has_point = false;
|
||||||
for (index, c) in s.char_indices() {
|
for (index, c) in s.char_indices() {
|
||||||
if c == '.' {
|
match (radix, c) {
|
||||||
|
(_, '.') => {
|
||||||
err!(has_point, TooManyPoints);
|
err!(has_point, TooManyPoints);
|
||||||
has_digits = false;
|
has_digits = false;
|
||||||
has_point = true;
|
has_point = true;
|
||||||
frac.0 = index + c.len_utf8();
|
frac.0 = index + c.len_utf8();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
match c {
|
(_, '+') => {
|
||||||
'+' => {
|
|
||||||
err!(has_point || has_sign || has_digits, InvalidDigit);
|
err!(has_point || has_sign || has_digits, InvalidDigit);
|
||||||
has_sign = true;
|
has_sign = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
'-' => {
|
(_, '-') => {
|
||||||
err!(
|
err!(
|
||||||
has_point || has_sign || has_digits || !can_be_neg,
|
has_point || has_sign || has_digits || !can_be_neg,
|
||||||
InvalidDigit
|
InvalidDigit
|
||||||
|
@ -240,7 +240,12 @@ fn parse(s: &str, can_be_neg: bool) -> Result<Parse<'_>, ParseFixedError> {
|
||||||
is_negative = true;
|
is_negative = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
'0'..='9' => {
|
(2, '0'..='1')
|
||||||
|
| (8, '0'..='7')
|
||||||
|
| (10, '0'..='9')
|
||||||
|
| (16, '0'..='9')
|
||||||
|
| (16, 'a'..='f')
|
||||||
|
| (16, 'A'..='F') => {
|
||||||
if !has_point && !has_digits {
|
if !has_point && !has_digits {
|
||||||
int.0 = index;
|
int.0 = index;
|
||||||
}
|
}
|
||||||
|
@ -276,7 +281,7 @@ macro_rules! impl_from_str {
|
||||||
type Err = ParseFixedError;
|
type Err = ParseFixedError;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
$method(s, Self::int_nbits(), Self::frac_nbits()).map(Self::from_bits)
|
$method(s, 10, Self::int_nbits(), Self::frac_nbits()).map(Self::from_bits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -284,16 +289,21 @@ macro_rules! impl_from_str {
|
||||||
|
|
||||||
macro_rules! impl_from_str_signed {
|
macro_rules! impl_from_str_signed {
|
||||||
(
|
(
|
||||||
($Fixed:ident, $NBits:ident, $Bits:ident, $HalfBits:ident, $DoubleBits:ident, $one:expr);
|
$Fixed:ident, $NBits:ident, $Bits:ident;
|
||||||
fn $all:ident;
|
fn $all:ident;
|
||||||
fn $int:ident, $int_half:expr;
|
fn $int:ident, ($int_half:ident, $int_half_cond:expr);
|
||||||
$frac:ident;
|
$frac:ident;
|
||||||
) => {
|
) => {
|
||||||
impl_from_str! { $Fixed, $NBits, $all }
|
impl_from_str! { $Fixed, $NBits, $all }
|
||||||
|
|
||||||
fn $all(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<$Bits, ParseFixedError> {
|
fn $all(
|
||||||
let Parse { neg, int, frac } = parse(s, true)?;
|
s: &str,
|
||||||
let (frac, whole_frac) = match $frac(frac, frac_nbits) {
|
radix: i32,
|
||||||
|
int_nbits: u32,
|
||||||
|
frac_nbits: u32,
|
||||||
|
) -> Result<$Bits, ParseFixedError> {
|
||||||
|
let Parse { neg, int, frac } = parse(s, true, 10)?;
|
||||||
|
let (frac, whole_frac) = match $frac(frac, radix, frac_nbits) {
|
||||||
Some(frac) => (frac, false),
|
Some(frac) => (frac, false),
|
||||||
None => (0, true),
|
None => (0, true),
|
||||||
};
|
};
|
||||||
|
@ -313,22 +323,19 @@ macro_rules! impl_from_str_signed {
|
||||||
} else {
|
} else {
|
||||||
frac as $Bits
|
frac as $Bits
|
||||||
};
|
};
|
||||||
let int = $int(neg, int, int_nbits, whole_frac)?;
|
let int = $int(neg, int, radix, int_nbits, whole_frac)?;
|
||||||
Ok(int | frac)
|
Ok(int | frac)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn $int(
|
fn $int(
|
||||||
neg: bool,
|
neg: bool,
|
||||||
int: &str,
|
int: &str,
|
||||||
|
radix: i32,
|
||||||
nbits: u32,
|
nbits: u32,
|
||||||
whole_frac: bool,
|
whole_frac: bool,
|
||||||
) -> Result<$Bits, ParseFixedError> {
|
) -> Result<$Bits, ParseFixedError> {
|
||||||
let half: Option<fn(bool, &str, u32, bool) -> Result<$HalfBits, ParseFixedError>> =
|
if $int_half_cond && nbits <= <$Bits as SealedInt>::NBITS / 2 {
|
||||||
$int_half;
|
return $int_half(neg, int, radix, nbits, whole_frac).map($Bits::from);
|
||||||
if let Some(half) = half {
|
|
||||||
if nbits <= <$Bits as SealedInt>::NBITS / 2 {
|
|
||||||
return half(neg, int, nbits, whole_frac).map($Bits::from);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut int = int;
|
let mut int = int;
|
||||||
while int.starts_with('0') {
|
while int.starts_with('0') {
|
||||||
|
@ -339,11 +346,11 @@ macro_rules! impl_from_str_signed {
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
let max_abs_int = if neg {
|
let max_abs_int = if neg {
|
||||||
$one << (nbits - 1)
|
<$Bits as SealedInt>::Unsigned::MSB
|
||||||
} else {
|
} else {
|
||||||
($one << (nbits - 1)) - 1
|
<$Bits as SealedInt>::Unsigned::MSB - 1
|
||||||
};
|
};
|
||||||
let mut acc = match int.parse::<$DoubleBits>() {
|
let mut acc = match int.parse::<<$Bits as SealedInt>::Unsigned>() {
|
||||||
Ok(i) => {
|
Ok(i) => {
|
||||||
err!(i > max_abs_int, Overflow);
|
err!(i > max_abs_int, Overflow);
|
||||||
i
|
i
|
||||||
|
@ -366,164 +373,36 @@ macro_rules! impl_from_str_signed {
|
||||||
|
|
||||||
macro_rules! impl_from_str_unsigned {
|
macro_rules! impl_from_str_unsigned {
|
||||||
(
|
(
|
||||||
($Fixed:ident, $NBits:ident, $Bits:ident, $HalfBits:ident, $DoubleBits:ident, $one:expr);
|
$Fixed:ident, $NBits:ident, $Bits:ident;
|
||||||
fn $all:ident;
|
fn $all:ident;
|
||||||
fn $int:ident, $int_half:expr;
|
fn $int:ident, ($int_half:ident, $int_half_cond:expr);
|
||||||
fn $frac:ident, $frac_half:expr;
|
$frac:ident;
|
||||||
$decode_frac:ident, $dec_frac_digits:expr;
|
|
||||||
) => {
|
) => {
|
||||||
impl_from_str! { $Fixed, $NBits, $all }
|
impl_from_str! { $Fixed, $NBits, $all }
|
||||||
|
|
||||||
fn $all(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<$Bits, ParseFixedError> {
|
fn $all(
|
||||||
let Parse { int, frac, .. } = parse(s, false)?;
|
s: &str,
|
||||||
let (frac, whole_frac) = match $frac(frac, frac_nbits) {
|
radix: i32,
|
||||||
|
int_nbits: u32,
|
||||||
|
frac_nbits: u32,
|
||||||
|
) -> Result<$Bits, ParseFixedError> {
|
||||||
|
let Parse { int, frac, .. } = parse(s, false, 10)?;
|
||||||
|
let (frac, whole_frac) = match $frac(frac, radix, frac_nbits) {
|
||||||
Some(frac) => (frac, false),
|
Some(frac) => (frac, false),
|
||||||
None => (0, true),
|
None => (0, true),
|
||||||
};
|
};
|
||||||
let int = $int(int, int_nbits, whole_frac)?;
|
let int = $int(int, radix, int_nbits, whole_frac)?;
|
||||||
Ok(int | frac)
|
Ok(int | frac)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn $int(int: &str, nbits: u32, whole_frac: bool) -> Result<$Bits, ParseFixedError> {
|
fn $int(
|
||||||
let half: Option<fn(&str, u32, bool) -> Result<$HalfBits, ParseFixedError>> = $int_half;
|
|
||||||
if let Some(half) = half {
|
|
||||||
if nbits <= <$Bits as SealedInt>::NBITS / 2 {
|
|
||||||
return half(int, nbits, whole_frac).map($Bits::from);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut int = int;
|
|
||||||
while int.starts_with('0') {
|
|
||||||
int = &int[1..];
|
|
||||||
}
|
|
||||||
if nbits == 0 {
|
|
||||||
err!(whole_frac || !int.is_empty(), Overflow);
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
let max_abs_int = ($one << nbits) - 1;
|
|
||||||
let mut acc = match int.parse::<$DoubleBits>() {
|
|
||||||
Ok(i) => {
|
|
||||||
err!(i > max_abs_int, Overflow);
|
|
||||||
i
|
|
||||||
}
|
|
||||||
Err(_) => err!(Overflow),
|
|
||||||
};
|
|
||||||
if whole_frac {
|
|
||||||
acc += 1;
|
|
||||||
err!(acc > max_abs_int, Overflow);
|
|
||||||
}
|
|
||||||
Ok((acc as $Bits) << (<$Bits as SealedInt>::NBITS - nbits))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn $frac(frac: &str, nbits: u32) -> Option<$Bits> {
|
|
||||||
let half: Option<fn(&str, u32) -> Option<$HalfBits>> = $frac_half;
|
|
||||||
if let Some(half) = half {
|
|
||||||
if nbits <= <$Bits as SealedInt>::NBITS / 2 {
|
|
||||||
return half(frac, nbits).map($Bits::from);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if frac.is_empty() {
|
|
||||||
return Some(0);
|
|
||||||
}
|
|
||||||
let end = cmp::min(frac.len(), $dec_frac_digits);
|
|
||||||
let rem = $dec_frac_digits - end;
|
|
||||||
let i = frac[..end].parse::<$DoubleBits>().unwrap() * ($one * 10).pow(rem as u32);
|
|
||||||
$decode_frac(i, <$Bits as SealedInt>::NBITS - nbits)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_str_signed! {
|
|
||||||
(FixedI8, U8, i8, bool, u16, 1u16);
|
|
||||||
fn from_str_i8;
|
|
||||||
fn get_int_i8, None;
|
|
||||||
get_frac8;
|
|
||||||
}
|
|
||||||
impl_from_str_unsigned! {
|
|
||||||
(FixedU8, U8, u8, bool, u16, 1u16);
|
|
||||||
fn from_str_u8;
|
|
||||||
fn get_int_u8, None;
|
|
||||||
fn get_frac8, None;
|
|
||||||
dec3_to_bin8, 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_str_signed! {
|
|
||||||
(FixedI16, U16, i16, i8, u32, 1u32);
|
|
||||||
fn from_str_i16;
|
|
||||||
fn get_int_i16, Some(get_int_i8);
|
|
||||||
get_frac16;
|
|
||||||
}
|
|
||||||
impl_from_str_unsigned! {
|
|
||||||
(FixedU16, U16, u16, u8, u32, 1u32);
|
|
||||||
fn from_str_u16;
|
|
||||||
fn get_int_u16, Some(get_int_u8);
|
|
||||||
fn get_frac16, Some(get_frac8);
|
|
||||||
dec6_to_bin16, 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_str_signed! {
|
|
||||||
(FixedI32, U32, i32, i16, u64, 1u64);
|
|
||||||
fn from_str_i32;
|
|
||||||
fn get_int_i32, Some(get_int_i16);
|
|
||||||
get_frac32;
|
|
||||||
}
|
|
||||||
impl_from_str_unsigned! {
|
|
||||||
(FixedU32, U32, u32, u16, u64, 1u64);
|
|
||||||
fn from_str_u32;
|
|
||||||
fn get_int_u32, Some(get_int_u16);
|
|
||||||
fn get_frac32, Some(get_frac16);
|
|
||||||
dec13_to_bin32, 13;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_str_signed! {
|
|
||||||
(FixedI64, U64, i64, i32, u128, 1u128);
|
|
||||||
fn from_str_i64;
|
|
||||||
fn get_int_i64, Some(get_int_i32);
|
|
||||||
get_frac64;
|
|
||||||
}
|
|
||||||
impl_from_str_unsigned! {
|
|
||||||
(FixedU64, U64, u64, u32, u128, 1u128);
|
|
||||||
fn from_str_u64;
|
|
||||||
fn get_int_u64, Some(get_int_u32);
|
|
||||||
fn get_frac64, Some(get_frac32);
|
|
||||||
dec27_to_bin64, 27;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_str! { FixedI128, U128, from_str_i128 }
|
|
||||||
|
|
||||||
fn from_str_i128(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<i128, ParseFixedError> {
|
|
||||||
let Parse { neg, int, frac } = parse(s, true)?;
|
|
||||||
let (frac, whole_frac) = match get_frac128(frac, frac_nbits) {
|
|
||||||
Some(frac) => (frac, false),
|
|
||||||
None => (0, true),
|
|
||||||
};
|
|
||||||
let frac = if frac_nbits == <i128>::NBITS {
|
|
||||||
// special case: no int bits
|
|
||||||
if neg {
|
|
||||||
if frac > <i128 as SealedInt>::Unsigned::MSB {
|
|
||||||
err!(Overflow)
|
|
||||||
}
|
|
||||||
frac.wrapping_neg() as i128
|
|
||||||
} else {
|
|
||||||
if frac >= <i128 as SealedInt>::Unsigned::MSB {
|
|
||||||
err!(Overflow)
|
|
||||||
}
|
|
||||||
frac as i128
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
frac as i128
|
|
||||||
};
|
|
||||||
let int = get_int_i128(neg, int, int_nbits, whole_frac)?;
|
|
||||||
Ok(int | frac)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_int_i128(
|
|
||||||
neg: bool,
|
|
||||||
int: &str,
|
int: &str,
|
||||||
|
radix: i32,
|
||||||
nbits: u32,
|
nbits: u32,
|
||||||
whole_frac: bool,
|
whole_frac: bool,
|
||||||
) -> Result<i128, ParseFixedError> {
|
) -> Result<$Bits, ParseFixedError> {
|
||||||
if nbits <= 64 {
|
if $int_half_cond && nbits <= <$Bits as SealedInt>::NBITS / 2 {
|
||||||
return get_int_i64(neg, int, nbits, whole_frac).map(i128::from);
|
return $int_half(int, radix, nbits, whole_frac).map($Bits::from);
|
||||||
}
|
}
|
||||||
let mut int = int;
|
let mut int = int;
|
||||||
while int.starts_with('0') {
|
while int.starts_with('0') {
|
||||||
|
@ -533,55 +412,7 @@ fn get_int_i128(
|
||||||
err!(whole_frac || !int.is_empty(), Overflow);
|
err!(whole_frac || !int.is_empty(), Overflow);
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
let max_abs_int = if neg {
|
let mut acc = match int.parse::<$Bits>() {
|
||||||
1u128 << (nbits - 1)
|
|
||||||
} else {
|
|
||||||
(1u128 << (nbits - 1)) - 1
|
|
||||||
};
|
|
||||||
let mut acc = match int.parse::<u128>() {
|
|
||||||
Ok(i) => {
|
|
||||||
err!(i > max_abs_int, Overflow);
|
|
||||||
i
|
|
||||||
}
|
|
||||||
Err(_) => err!(Overflow),
|
|
||||||
};
|
|
||||||
if whole_frac {
|
|
||||||
acc += 1;
|
|
||||||
err!(acc > max_abs_int, Overflow);
|
|
||||||
}
|
|
||||||
let signed = if neg {
|
|
||||||
acc.wrapping_neg() as i128
|
|
||||||
} else {
|
|
||||||
acc as i128
|
|
||||||
};
|
|
||||||
Ok(signed << (<i128>::NBITS - nbits))
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_from_str! { FixedU128, U128, from_str_u128 }
|
|
||||||
|
|
||||||
fn from_str_u128(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<u128, ParseFixedError> {
|
|
||||||
let Parse { int, frac, .. } = parse(s, false)?;
|
|
||||||
let (frac, whole_frac) = match get_frac128(frac, frac_nbits) {
|
|
||||||
Some(frac) => (frac, false),
|
|
||||||
None => (0, true),
|
|
||||||
};
|
|
||||||
let int = get_int_u128(int, int_nbits, whole_frac)?;
|
|
||||||
Ok(int | frac)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_int_u128(int: &str, nbits: u32, whole_frac: bool) -> Result<u128, ParseFixedError> {
|
|
||||||
if nbits <= 64 {
|
|
||||||
return get_int_u64(int, nbits, whole_frac).map(u128::from);
|
|
||||||
}
|
|
||||||
let mut int = int;
|
|
||||||
while int.starts_with('0') {
|
|
||||||
int = &int[1..];
|
|
||||||
}
|
|
||||||
if nbits == 0 {
|
|
||||||
err!(whole_frac || !int.is_empty(), Overflow);
|
|
||||||
return Ok(0);
|
|
||||||
}
|
|
||||||
let mut acc = match int.parse::<u128>() {
|
|
||||||
Ok(i) => i,
|
Ok(i) => i,
|
||||||
Err(_) => err!(Overflow),
|
Err(_) => err!(Overflow),
|
||||||
};
|
};
|
||||||
|
@ -591,12 +422,114 @@ fn get_int_u128(int: &str, nbits: u32, whole_frac: bool) -> Result<u128, ParseFi
|
||||||
(_, true) => err!(Overflow),
|
(_, true) => err!(Overflow),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(acc << (<u128 as SealedInt>::NBITS - nbits))
|
Ok(acc << (<$Bits as SealedInt>::NBITS - nbits))
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_frac128(frac: &str, nbits: u32) -> Option<u128> {
|
macro_rules! impl_from_str_unsigned_not128 {
|
||||||
|
(
|
||||||
|
$Fixed:ident, $NBits:ident, $Bits:ident;
|
||||||
|
fn $all:ident;
|
||||||
|
fn $int:ident, ($int_half:ident, $int_half_cond:expr);
|
||||||
|
fn $frac:ident, ($frac_half:ident, $frac_half_cond:expr);
|
||||||
|
$decode_frac:ident, $dec_frac_digits:expr, $DoubleBits:ident;
|
||||||
|
) => {
|
||||||
|
impl_from_str_unsigned! {
|
||||||
|
$Fixed, $NBits, $Bits;
|
||||||
|
fn $all;
|
||||||
|
fn $int, ($int_half, $int_half_cond);
|
||||||
|
$frac;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn $frac(frac: &str, radix: i32, nbits: u32) -> Option<$Bits> {
|
||||||
|
if $frac_half_cond && nbits <= <$Bits as SealedInt>::NBITS / 2 {
|
||||||
|
return $frac_half(frac, radix, nbits).map($Bits::from);
|
||||||
|
}
|
||||||
|
if frac.is_empty() {
|
||||||
|
return Some(0);
|
||||||
|
}
|
||||||
|
let end = cmp::min(frac.len(), $dec_frac_digits);
|
||||||
|
let rem = $dec_frac_digits - end;
|
||||||
|
let ten: $DoubleBits = 10;
|
||||||
|
let i = frac[..end].parse::<$DoubleBits>().unwrap() * ten.pow(rem as u32);
|
||||||
|
$decode_frac(i, <$Bits as SealedInt>::NBITS - nbits)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_str_signed! {
|
||||||
|
FixedI8, U8, i8;
|
||||||
|
fn from_str_i8;
|
||||||
|
fn get_int_i8, (get_int_i8, false);
|
||||||
|
get_frac8;
|
||||||
|
}
|
||||||
|
impl_from_str_unsigned_not128! {
|
||||||
|
FixedU8, U8, u8;
|
||||||
|
fn from_str_u8;
|
||||||
|
fn get_int_u8, (get_int_u8, false);
|
||||||
|
fn get_frac8, (get_frac8, false);
|
||||||
|
dec3_to_bin8, 3, u16;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_str_signed! {
|
||||||
|
FixedI16, U16, i16;
|
||||||
|
fn from_str_i16;
|
||||||
|
fn get_int_i16, (get_int_i8, true);
|
||||||
|
get_frac16;
|
||||||
|
}
|
||||||
|
impl_from_str_unsigned_not128! {
|
||||||
|
FixedU16, U16, u16;
|
||||||
|
fn from_str_u16;
|
||||||
|
fn get_int_u16, (get_int_u8, true);
|
||||||
|
fn get_frac16, (get_frac8, true);
|
||||||
|
dec6_to_bin16, 6, u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_str_signed! {
|
||||||
|
FixedI32, U32, i32;
|
||||||
|
fn from_str_i32;
|
||||||
|
fn get_int_i32, (get_int_i16, true);
|
||||||
|
get_frac32;
|
||||||
|
}
|
||||||
|
impl_from_str_unsigned_not128! {
|
||||||
|
FixedU32, U32, u32;
|
||||||
|
fn from_str_u32;
|
||||||
|
fn get_int_u32, (get_int_u16, true);
|
||||||
|
fn get_frac32, (get_frac16, true);
|
||||||
|
dec13_to_bin32, 13, u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_str_signed! {
|
||||||
|
FixedI64, U64, i64;
|
||||||
|
fn from_str_i64;
|
||||||
|
fn get_int_i64, (get_int_i32, true);
|
||||||
|
get_frac64;
|
||||||
|
}
|
||||||
|
impl_from_str_unsigned_not128! {
|
||||||
|
FixedU64, U64, u64;
|
||||||
|
fn from_str_u64;
|
||||||
|
fn get_int_u64, (get_int_u32, true);
|
||||||
|
fn get_frac64, (get_frac32, true);
|
||||||
|
dec27_to_bin64, 27, u128;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_str_signed! {
|
||||||
|
FixedI128, U128, i128;
|
||||||
|
fn from_str_i128;
|
||||||
|
fn get_int_i128, (get_int_i64, true);
|
||||||
|
get_frac128;
|
||||||
|
}
|
||||||
|
impl_from_str_unsigned! {
|
||||||
|
FixedU128, U128, u128;
|
||||||
|
fn from_str_u128;
|
||||||
|
fn get_int_u128, (get_int_u64, true);
|
||||||
|
get_frac128;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_frac128(frac: &str, radix: i32, nbits: u32) -> Option<u128> {
|
||||||
if nbits <= 64 {
|
if nbits <= 64 {
|
||||||
return get_frac64(frac, nbits).map(u128::from);
|
return get_frac64(frac, radix, nbits).map(u128::from);
|
||||||
}
|
}
|
||||||
if frac.is_empty() {
|
if frac.is_empty() {
|
||||||
return Some(0);
|
return Some(0);
|
||||||
|
@ -744,26 +677,26 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_parse_bounds() {
|
fn check_parse_bounds() {
|
||||||
let Parse { neg, int, frac } = parse("-12.34", true).unwrap();
|
let Parse { neg, int, frac } = parse("-12.34", true, 10).unwrap();
|
||||||
assert_eq!((neg, int, frac), (true, "12", "34"));
|
assert_eq!((neg, int, frac), (true, "12", "34"));
|
||||||
let Parse { neg, int, frac } = parse("12.", true).unwrap();
|
let Parse { neg, int, frac } = parse("12.", true, 10).unwrap();
|
||||||
assert_eq!((neg, int, frac), (false, "12", ""));
|
assert_eq!((neg, int, frac), (false, "12", ""));
|
||||||
let Parse { neg, int, frac } = parse("+.34", false).unwrap();
|
let Parse { neg, int, frac } = parse("+.34", false, 10).unwrap();
|
||||||
assert_eq!((neg, int, frac), (false, "", "34"));
|
assert_eq!((neg, int, frac), (false, "", "34"));
|
||||||
let Parse { neg, int, frac } = parse("0", false).unwrap();
|
let Parse { neg, int, frac } = parse("0", false, 10).unwrap();
|
||||||
assert_eq!((neg, int, frac), (false, "0", ""));
|
assert_eq!((neg, int, frac), (false, "0", ""));
|
||||||
|
|
||||||
let ParseFixedError { kind } = parse("0 ", true).unwrap_err();
|
let ParseFixedError { kind } = parse("0 ", true, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
||||||
let ParseFixedError { kind } = parse("+.", true).unwrap_err();
|
let ParseFixedError { kind } = parse("+.", true, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::NoDigits);
|
assert_eq!(kind, ParseErrorKind::NoDigits);
|
||||||
let ParseFixedError { kind } = parse(".1.", true).unwrap_err();
|
let ParseFixedError { kind } = parse(".1.", true, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::TooManyPoints);
|
assert_eq!(kind, ParseErrorKind::TooManyPoints);
|
||||||
let ParseFixedError { kind } = parse("1+2", true).unwrap_err();
|
let ParseFixedError { kind } = parse("1+2", true, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
||||||
let ParseFixedError { kind } = parse("1-2", true).unwrap_err();
|
let ParseFixedError { kind } = parse("1-2", true, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
||||||
let ParseFixedError { kind } = parse("-12", false).unwrap_err();
|
let ParseFixedError { kind } = parse("-12", false, 10).unwrap_err();
|
||||||
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue