macro_rules! decl_decimal_from_str {
(wide $Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::str::FromStr for $Type<SCALE> {
type Err = $crate::types::widths::ParseError;
fn from_str(s: &str) -> ::core::result::Result<Self, Self::Err> {
let comps = $crate::support::display::parse_components::<SCALE>(s)?;
let negative = comps.negative;
let int_str = comps.int_str;
let frac_str = comps.frac_str;
let ten = <$Storage>::from_i128(10);
let multiplier = <$Storage>::pow(ten, SCALE);
let zero = <$Storage>::from_i128(0);
let mut int_value = zero;
for &b in int_str {
let digit = <$Storage>::from_i128((b - b'0') as i128);
let scaled = match <$Storage>::checked_mul(int_value, ten) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
};
int_value = if negative {
match <$Storage>::checked_sub(scaled, digit) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
}
} else {
match <$Storage>::checked_add(scaled, digit) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
}
};
}
let int_scaled = match <$Storage>::checked_mul(int_value, multiplier) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
};
let mut frac_value = zero;
let frac_len = frac_str.len();
for &b in frac_str {
let digit = <$Storage>::from_i128((b - b'0') as i128);
let scaled = match <$Storage>::checked_mul(frac_value, ten) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
};
frac_value = if negative {
match <$Storage>::checked_sub(scaled, digit) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
}
} else {
match <$Storage>::checked_add(scaled, digit) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
}
};
}
let pad = (SCALE as usize) - frac_len;
if pad > 0 {
let pad_factor = <$Storage>::pow(ten, pad as u32);
frac_value = match <$Storage>::checked_mul(frac_value, pad_factor) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
};
}
let combined = match <$Storage>::checked_add(int_scaled, frac_value) {
::core::option::Option::Some(v) => v,
::core::option::Option::None => {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
)
}
};
::core::result::Result::Ok(Self(combined))
}
}
};
($Type:ident, $Storage:ty) => {
impl<const SCALE: u32> ::core::str::FromStr for $Type<SCALE> {
type Err = $crate::types::widths::ParseError;
fn from_str(s: &str) -> ::core::result::Result<Self, Self::Err> {
let bits_i128 = $crate::support::display::parse_decimal_bits::<SCALE>(s)?;
if bits_i128 > <$Storage>::MAX as i128 || bits_i128 < <$Storage>::MIN as i128 {
return ::core::result::Result::Err(
$crate::types::widths::ParseError::OutOfRange,
);
}
::core::result::Result::Ok(Self(bits_i128 as $Storage))
}
}
};
}
pub(crate) use decl_decimal_from_str;