diff --git a/src/display.rs b/src/display.rs index a2c9348..bfdf416 100644 --- a/src/display.rs +++ b/src/display.rs @@ -36,13 +36,22 @@ where type Err = ParseDecimalError; fn from_str(s: &str) -> Result { + if s.is_empty() { + return Err(ParseDecimalError::EmptyString); + } + // Strip the sign (-0 would parse to 0 and break our output). let unsigned_s = s.strip_prefix('-').unwrap_or(s); // Parse the unsigned representation. - let (integer_s, fractional_s) = unsigned_s - .split_once('.') - .ok_or(ParseDecimalError::MissingDecimalPoint)?; + let Some((integer_s, fractional_s)) = unsigned_s.split_once('.') else { + // The number does not contain a decimal point, but we can still try and parse + // it as an integer. + let integer = I::from_str(s)?; + + return Decimal::try_from_scaled(integer, 0) + .ok_or(ParseDecimalError::Overflow(integer, I::ZERO)); + }; let integer = I::from_str(integer_s)?; let fractional = I::from_str(fractional_s)?; @@ -86,6 +95,8 @@ pub enum ParseDecimalError where I: Display, { + #[error("Empty string provided")] + EmptyString, #[error("Missing decimal point")] MissingDecimalPoint, #[error("Resultant decimal overflowed; integer={0}; fractional={1}")] @@ -120,7 +131,7 @@ mod tests { #[test] fn uint64_9_from_str() { - assert_eq!("".parse::(), Err(ParseDecimalError::MissingDecimalPoint)); + assert_eq!("".parse::(), Err(ParseDecimalError::EmptyString)); expect![[r#" Err( ParseInt( @@ -132,6 +143,8 @@ mod tests { "#]] .assert_debug_eq(&"1.".parse::()); assert_eq!("1.0".parse::(), Ok(Uint64_9::ONE)); + assert_eq!("10.0".parse::(), Ok(Uint64_9::try_from_scaled(10, 0).unwrap())); + assert_eq!("10".parse::(), Ok(Uint64_9::try_from_scaled(10, 0).unwrap())); assert_eq!("0.1".parse::(), Ok(Decimal(10u64.pow(8)))); assert_eq!("0.123456789".parse::(), Ok(Decimal(123456789))); assert_eq!("0.012345678".parse::(), Ok(Decimal(12345678))); @@ -172,7 +185,7 @@ mod tests { #[test] fn int64_9_from_str() { - assert_eq!("".parse::(), Err(ParseDecimalError::MissingDecimalPoint)); + assert_eq!("".parse::(), Err(ParseDecimalError::EmptyString)); expect![[r#" Err( ParseInt( @@ -190,6 +203,8 @@ mod tests { assert_eq!("0.000000001".parse::(), Ok(Decimal(1))); assert_eq!("0.0000000001".parse::(), Err(ParseDecimalError::PrecisionLoss(10))); assert_eq!("-1.0".parse::(), Ok(-Int64_9::ONE)); + assert_eq!("-10.0".parse::(), Ok(Int64_9::try_from_scaled(-10, 0).unwrap())); + assert_eq!("-10".parse::(), Ok(Int64_9::try_from_scaled(-10, 0).unwrap())); assert_eq!("-0.1".parse::(), Ok(-Decimal(10i64.pow(8)))); assert_eq!("-0.123456789".parse::(), Ok(-Decimal(123456789))); assert_eq!("-0.012345678".parse::(), Ok(-Decimal(12345678))); diff --git a/src/lib.rs b/src/lib.rs index dc69a7f..fb09aa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,4 +24,5 @@ pub(crate) mod algorithms; pub use aliases::*; pub use decimal::*; +pub use display::ParseDecimalError; pub use integer::*;