diff --git a/src/from_str.rs b/src/from_str.rs index 0c94fe6..b6d76a7 100644 --- a/src/from_str.rs +++ b/src/from_str.rs @@ -332,7 +332,7 @@ macro_rules! impl_from_str_signed { ( $Fixed:ident, $NBits:ident, $Bits:ident; fn $all:ident; - fn $int:ident, ($int_half:ident, $int_half_cond:expr); + $int:ident; $frac:ident; ) => { impl_from_str! { $Fixed, $NBits, $all } @@ -348,64 +348,20 @@ macro_rules! impl_from_str_signed { Some(frac) => (frac, false), None => (0, true), }; - if frac_nbits == <$Bits>::NBITS { - // special case: no int bits - let max_abs = if neg { - <$Bits as SealedInt>::Unsigned::MSB - } else { - <$Bits as SealedInt>::Unsigned::MSB - 1 - }; - err!(abs_frac > max_abs, Overflow); - } - let frac = if neg { - abs_frac.wrapping_neg() as $Bits - } else { - abs_frac as $Bits - }; - let int = $int(neg, int, radix, int_nbits, whole_frac)?; - Ok(int + frac) - } - - fn $int( - neg: bool, - int: &str, - radix: u32, - nbits: u32, - whole_frac: bool, - ) -> Result<$Bits, ParseFixedError> { - if $int_half_cond && nbits <= <$Bits as SealedInt>::NBITS / 2 { - return $int_half(neg, int, radix, 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 = if neg { + let abs_int = $int(int, radix, int_nbits, whole_frac)?; + let abs = abs_int | abs_frac; + let max_abs = if neg { <$Bits as SealedInt>::Unsigned::MSB } else { <$Bits as SealedInt>::Unsigned::MSB - 1 }; - let mut acc = match <$Bits as SealedInt>::Unsigned::from_str_radix(int, radix) { - 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 $Bits + err!(abs > max_abs, Overflow); + let f = if neg { + abs.wrapping_neg() as $Bits } else { - acc as $Bits + abs as $Bits }; - Ok(signed << (<$Bits>::NBITS - nbits)) + Ok(f) } }; } @@ -440,8 +396,9 @@ macro_rules! impl_from_str_unsigned { nbits: u32, whole_frac: bool, ) -> Result<$Bits, ParseFixedError> { - if $int_half_cond && nbits <= <$Bits as SealedInt>::NBITS / 2 { - return $int_half(int, radix, nbits, whole_frac).map($Bits::from); + const HALF: u32 = <$Bits as SealedInt>::NBITS / 2; + if $int_half_cond && nbits <= HALF { + return $int_half(int, radix, nbits, whole_frac).map(|x| $Bits::from(x) << HALF); } let mut int = int; while int.starts_with('0') { @@ -461,7 +418,9 @@ macro_rules! impl_from_str_unsigned { (_, true) => err!(Overflow), }; } - Ok(acc << (<$Bits as SealedInt>::NBITS - nbits)) + let remove_bits = <$Bits as SealedInt>::NBITS - nbits; + err!(remove_bits > 0 && (acc >> nbits) != 0, Overflow); + Ok(acc << remove_bits) } }; } @@ -506,13 +465,13 @@ macro_rules! impl_from_str_unsigned_not128 { impl_from_str_signed! { FixedI8, U8, i8; fn from_str_i8; - fn get_int_i8, (get_int_i8, false); + get_int8; get_frac8; } impl_from_str_unsigned_not128! { FixedU8, U8, u8; fn from_str_u8; - fn get_int_u8, (get_int_u8, false); + fn get_int8, (get_int8, false); fn get_frac8, (get_frac8, false); dec3_to_bin8, 3, u16; } @@ -520,13 +479,13 @@ impl_from_str_unsigned_not128! { impl_from_str_signed! { FixedI16, U16, i16; fn from_str_i16; - fn get_int_i16, (get_int_i8, true); + get_int16; get_frac16; } impl_from_str_unsigned_not128! { FixedU16, U16, u16; fn from_str_u16; - fn get_int_u16, (get_int_u8, true); + fn get_int16, (get_int8, true); fn get_frac16, (get_frac8, true); dec6_to_bin16, 6, u32; } @@ -534,13 +493,13 @@ impl_from_str_unsigned_not128! { impl_from_str_signed! { FixedI32, U32, i32; fn from_str_i32; - fn get_int_i32, (get_int_i16, true); + get_int32; get_frac32; } impl_from_str_unsigned_not128! { FixedU32, U32, u32; fn from_str_u32; - fn get_int_u32, (get_int_u16, true); + fn get_int32, (get_int16, true); fn get_frac32, (get_frac16, true); dec13_to_bin32, 13, u64; } @@ -548,13 +507,13 @@ impl_from_str_unsigned_not128! { impl_from_str_signed! { FixedI64, U64, i64; fn from_str_i64; - fn get_int_i64, (get_int_i32, true); + get_int64; get_frac64; } impl_from_str_unsigned_not128! { FixedU64, U64, u64; fn from_str_u64; - fn get_int_u64, (get_int_u32, true); + fn get_int64, (get_int32, true); fn get_frac64, (get_frac32, true); dec27_to_bin64, 27, u128; } @@ -562,13 +521,13 @@ impl_from_str_unsigned_not128! { impl_from_str_signed! { FixedI128, U128, i128; fn from_str_i128; - fn get_int_i128, (get_int_i64, true); + get_int128; get_frac128; } impl_from_str_unsigned! { FixedU128, U128, u128; fn from_str_u128; - fn get_int_u128, (get_int_u64, true); + fn get_int128, (get_int64, true); get_frac128; } @@ -757,7 +716,7 @@ mod tests { { match s.parse::() { Ok(f) => assert_eq!(f.to_bits(), bits), - Err(ParseFixedError { .. }) => panic!("could not parse {}", s), + Err(e) => panic!("could not parse {}: {}", s, e), } } fn assert_err(s: &str, kind: ParseErrorKind) @@ -765,7 +724,7 @@ mod tests { F: Fixed + FromStr, { match s.parse::() { - Ok(_) => panic!("incorrectly parsed {}", s), + Ok(f) => panic!("incorrectly parsed {} as {}", s, f), Err(ParseFixedError { kind: err }) => assert_eq!(err, kind), } } @@ -774,30 +733,37 @@ mod tests { fn check_i8_u8_from_str() { use crate::types::*; + assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-0.502", ParseErrorKind::Overflow); + assert_ok::("-0.501", -0x80); assert_ok::("0.498", 0x7F); assert_err::("0.499", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_ok::("-0.501", -0x80); - assert_err::("-0.502", ParseErrorKind::Overflow); - assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-8.04", ParseErrorKind::Overflow); + assert_ok::("-8.03", -0x80); + assert_ok::("7.96", 0x7F); + assert_err::("7.97", ParseErrorKind::Overflow); - assert_ok::("000127.499", 0x7F); + assert_err::("-128.5", ParseErrorKind::Overflow); + assert_ok::("-128.499", -0x80); + assert_ok::("127.499", 0x7F); assert_err::("127.5", ParseErrorKind::Overflow); - assert_ok::("-128.499", -0x80); - assert_err::("-128.5", ParseErrorKind::Overflow); - + assert_err::("-0", ParseErrorKind::InvalidDigit); assert_ok::("0.498", 0x7F); assert_ok::("0.499", 0x80); assert_ok::("0.998", 0xFF); assert_err::("0.999", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_err::("-0", ParseErrorKind::InvalidDigit); + assert_ok::("7.96", 0x7F); + assert_ok::("7.97", 0x80); + assert_ok::("15.96", 0xFF); + assert_err::("15.97", ParseErrorKind::Overflow); - assert_ok::("000127.499", 0x7F); - assert_ok::("000127.5", 0x80); + assert_ok::("127.499", 0x7F); + assert_ok::("127.5", 0x80); assert_ok::("255.499", 0xFF); assert_err::("255.5", ParseErrorKind::Overflow); } @@ -806,30 +772,37 @@ mod tests { fn check_i16_u16_from_str() { use crate::types::*; + assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-0.500008", ParseErrorKind::Overflow); + assert_ok::("-0.500007", -0x8000); assert_ok::("0.499992", 0x7FFF); assert_err::("0.499993", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_ok::("-0.500007", -0x8000); - assert_err::("-0.500008", ParseErrorKind::Overflow); - assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-128.002", ParseErrorKind::Overflow); + assert_ok::("-128.001", -0x8000); + assert_ok::("127.998", 0x7FFF); + assert_err::("127.999", ParseErrorKind::Overflow); - assert_ok::("00032767.499999", 0x7FFF); + assert_err::("-32768.5", ParseErrorKind::Overflow); + assert_ok::("-32768.499999", -0x8000); + assert_ok::("32767.499999", 0x7FFF); assert_err::("32767.5", ParseErrorKind::Overflow); - assert_ok::("-32768.499999", -0x8000); - assert_err::("-32768.5", ParseErrorKind::Overflow); - + assert_err::("-0", ParseErrorKind::InvalidDigit); assert_ok::("0.499992", 0x7FFF); assert_ok::("0.499993", 0x8000); assert_ok::("0.999992", 0xFFFF); assert_err::("0.999993", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_err::("-0", ParseErrorKind::InvalidDigit); + assert_ok::("127.998", 0x7FFF); + assert_ok::("127.999", 0x8000); + assert_ok::("255.998", 0xFFFF); + assert_err::("255.999", ParseErrorKind::Overflow); - assert_ok::("00032767.499999", 0x7FFF); - assert_ok::("00032767.5", 0x8000); + assert_ok::("32767.499999", 0x7FFF); + assert_ok::("32767.5", 0x8000); assert_ok::("65535.499999", 0xFFFF); assert_err::("65535.5", ParseErrorKind::Overflow); } @@ -838,30 +811,37 @@ mod tests { fn check_i32_u32_from_str() { use crate::types::*; + assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-0.5000000002", ParseErrorKind::Overflow); + assert_ok::("-0.5000000001", -0x8000_0000); assert_ok::("0.4999999998", 0x7FFF_FFFF); assert_err::("0.4999999999", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_ok::("-0.5000000001", -0x8000_0000); - assert_err::("-0.5000000002", ParseErrorKind::Overflow); - assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-32768.000008", ParseErrorKind::Overflow); + assert_ok::("-32768.000007", -0x8000_0000); + assert_ok::("32767.999992", 0x7FFF_FFFF); + assert_err::("32767.999993", ParseErrorKind::Overflow); - assert_ok::("0002147483647.4999999999", 0x7FFF_FFFF); + assert_err::("-2147483648.5", ParseErrorKind::Overflow); + assert_ok::("-2147483648.4999999999", -0x8000_0000); + assert_ok::("2147483647.4999999999", 0x7FFF_FFFF); assert_err::("2147483647.5", ParseErrorKind::Overflow); - assert_ok::("-2147483648.499999", -0x8000_0000); - assert_err::("-2147483648.5", ParseErrorKind::Overflow); - + assert_err::("-0", ParseErrorKind::InvalidDigit); assert_ok::("0.4999999998", 0x7FFF_FFFF); assert_ok::("0.4999999999", 0x8000_0000); assert_ok::("0.9999999998", 0xFFFF_FFFF); assert_err::("0.9999999999", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_err::("-0", ParseErrorKind::InvalidDigit); + assert_ok::("32767.999992", 0x7FFF_FFFF); + assert_ok::("32767.999993", 0x8000_0000); + assert_ok::("65535.999992", 0xFFFF_FFFF); + assert_err::("65535.999993", ParseErrorKind::Overflow); - assert_ok::("0002147483647.4999999999", 0x7FFF_FFFF); - assert_ok::("0002147483647.5", 0x8000_0000); + assert_ok::("2147483647.4999999999", 0x7FFF_FFFF); + assert_ok::("2147483647.5", 0x8000_0000); assert_ok::("4294967295.4999999999", 0xFFFF_FFFF); assert_err::("4294967295.5", ParseErrorKind::Overflow); } @@ -870,39 +850,46 @@ mod tests { fn check_i64_u64_from_str() { use crate::types::*; + assert_err::("-1", ParseErrorKind::Overflow); + assert_err::("-0.50000000000000000003", ParseErrorKind::Overflow); + assert_ok::("-0.50000000000000000002", -0x8000_0000_0000_0000); assert_ok::("0.49999999999999999997", 0x7FFF_FFFF_FFFF_FFFF); assert_err::("0.49999999999999999998", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_ok::("-0.50000000000000000002", -0x8000_0000_0000_0000); - assert_err::("-0.50000000000000000003", ParseErrorKind::Overflow); - assert_err::("-1", ParseErrorKind::Overflow); - - assert_ok::( - "0009223372036854775807.49999999999999999999", - 0x7FFF_FFFF_FFFF_FFFF, - ); - assert_err::("9223372036854775807.5", ParseErrorKind::Overflow); + assert_err::("-2147483648.0000000002", ParseErrorKind::Overflow); + assert_ok::("-2147483648.0000000001", -0x8000_0000_0000_0000); + assert_ok::("2147483647.9999999998", 0x7FFF_FFFF_FFFF_FFFF); + assert_err::("2147483647.9999999999", ParseErrorKind::Overflow); + assert_err::("-9223372036854775808.5", ParseErrorKind::Overflow); assert_ok::( "-9223372036854775808.49999999999999999999", -0x8000_0000_0000_0000, ); - assert_err::("-9223372036854775808.5", ParseErrorKind::Overflow); + assert_ok::( + "9223372036854775807.49999999999999999999", + 0x7FFF_FFFF_FFFF_FFFF, + ); + assert_err::("9223372036854775807.5", ParseErrorKind::Overflow); + assert_err::("-0", ParseErrorKind::InvalidDigit); assert_ok::("0.49999999999999999997", 0x7FFF_FFFF_FFFF_FFFF); assert_ok::("0.49999999999999999998", 0x8000_0000_0000_0000); assert_ok::("0.99999999999999999997", 0xFFFF_FFFF_FFFF_FFFF); assert_err::("0.99999999999999999998", ParseErrorKind::Overflow); assert_err::("1", ParseErrorKind::Overflow); - assert_err::("-0", ParseErrorKind::InvalidDigit); + assert_ok::("2147483647.9999999998", 0x7FFF_FFFF_FFFF_FFFF); + assert_ok::("2147483647.9999999999", 0x8000_0000_0000_0000); + assert_ok::("4294967295.9999999998", 0xFFFF_FFFF_FFFF_FFFF); + assert_err::("4294967295.9999999999", ParseErrorKind::Overflow); assert_ok::( - "0009223372036854775807.49999999999999999999", + "9223372036854775807.49999999999999999999", 0x7FFF_FFFF_FFFF_FFFF, ); - assert_ok::("0009223372036854775807.5", 0x8000_0000_0000_0000); + assert_ok::("9223372036854775807.5", 0x8000_0000_0000_0000); assert_ok::( "18446744073709551615.49999999999999999999", 0xFFFF_FFFF_FFFF_FFFF, @@ -914,6 +901,15 @@ mod tests { fn check_i128_u128_from_str() { use crate::types::*; + assert_err::("-1", ParseErrorKind::Overflow); + assert_err::( + "-0.500000000000000000000000000000000000002", + ParseErrorKind::Overflow, + ); + assert_ok::( + "-0.500000000000000000000000000000000000001", + -0x8000_0000_0000_0000_0000_0000_0000_0000, + ); assert_ok::( "0.499999999999999999999999999999999999998", 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, @@ -924,18 +920,33 @@ mod tests { ); assert_err::("1", ParseErrorKind::Overflow); - assert_ok::( - "-0.500000000000000000000000000000000000001", - -0x8000_0000_0000_0000_0000_0000_0000_0000, - ); - assert_err::( - "-0.500000000000000000000000000000000000002", + assert_err::( + "-9223372036854775808.00000000000000000003", + ParseErrorKind::Overflow, + ); + assert_ok::( + "-9223372036854775808.00000000000000000002", + -0x8000_0000_0000_0000_0000_0000_0000_0000, + ); + assert_ok::( + "9223372036854775807.99999999999999999997", + 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, + ); + assert_err::( + "9223372036854775807.99999999999999999998", ParseErrorKind::Overflow, ); - assert_err::("-1", ParseErrorKind::Overflow); + assert_err::( + "-170141183460469231731687303715884105728.5", + ParseErrorKind::Overflow, + ); assert_ok::( - "000170141183460469231731687303715884105727.4999999999999999999999999999999999999999", + "-170141183460469231731687303715884105728.4999999999999999999999999999999999999999", + -0x8000_0000_0000_0000_0000_0000_0000_0000, + ); + assert_ok::( + "170141183460469231731687303715884105727.4999999999999999999999999999999999999999", 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, ); assert_err::( @@ -943,15 +954,7 @@ mod tests { ParseErrorKind::Overflow, ); - assert_ok::( - "-170141183460469231731687303715884105728.4999999999999999999999999999999999999999", - -0x8000_0000_0000_0000_0000_0000_0000_0000, - ); - assert_err::( - "-170141183460469231731687303715884105728.5", - ParseErrorKind::Overflow, - ); - + assert_err::("-0", ParseErrorKind::InvalidDigit); assert_ok::( "0.499999999999999999999999999999999999998", 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, @@ -970,14 +973,29 @@ mod tests { ); assert_err::("1", ParseErrorKind::Overflow); - assert_err::("-0", ParseErrorKind::InvalidDigit); + assert_ok::( + "9223372036854775807.99999999999999999997", + 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, + ); + assert_ok::( + "9223372036854775807.99999999999999999998", + 0x8000_0000_0000_0000_0000_0000_0000_0000, + ); + assert_ok::( + "18446744073709551615.99999999999999999997", + 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, + ); + assert_err::( + "18446744073709551615.99999999999999999998", + ParseErrorKind::Overflow, + ); assert_ok::( - "000170141183460469231731687303715884105727.4999999999999999999999999999999999999999", + "170141183460469231731687303715884105727.4999999999999999999999999999999999999999", 0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF, ); assert_ok::( - "000170141183460469231731687303715884105727.5", + "170141183460469231731687303715884105727.5", 0x8000_0000_0000_0000_0000_0000_0000_0000, ); assert_ok::(