generatlize FromStr from Fixed{I8,U8} and do Fixed{I16,U16}
This commit is contained in:
parent
05980077b7
commit
34b14cd4e9
|
@ -226,7 +226,7 @@ fn dec_int_digits(int_bits: u32) -> u32 {
|
|||
(int_bits * 3 + i) / 10
|
||||
}
|
||||
|
||||
pub fn dec_frac_digits(frac_bits: u32) -> u32 {
|
||||
fn dec_frac_digits(frac_bits: u32) -> u32 {
|
||||
assert!(frac_bits < 299);
|
||||
let i = if frac_bits >= 196 {
|
||||
12
|
||||
|
|
237
src/from_str.rs
237
src/from_str.rs
|
@ -14,10 +14,10 @@
|
|||
// <https://opensource.org/licenses/MIT>.
|
||||
|
||||
use crate::{
|
||||
display,
|
||||
frac::{IsLessOrEqual, True, Unsigned, U8},
|
||||
frac::{IsLessOrEqual, True, Unsigned, U16, U8},
|
||||
sealed::SealedInt,
|
||||
wide_div::WideDivRem,
|
||||
FixedI8, FixedU8,
|
||||
FixedI16, FixedI8, FixedU16, FixedU8,
|
||||
};
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
|
@ -248,65 +248,62 @@ fn parse(s: &str, can_be_neg: bool) -> Result<Parse<'_>, ParseFixedError> {
|
|||
})
|
||||
}
|
||||
|
||||
impl<Frac> FromStr for FixedI8<Frac>
|
||||
where
|
||||
Frac: Unsigned + IsLessOrEqual<U8, Output = True>,
|
||||
{
|
||||
macro_rules! impl_from_str {
|
||||
($Fixed:ident, $NBits:ident, $method:ident) => {
|
||||
impl<Frac> FromStr for $Fixed<Frac>
|
||||
where
|
||||
Frac: Unsigned + IsLessOrEqual<$NBits, Output = True>,
|
||||
{
|
||||
type Err = ParseFixedError;
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
from_str_i8(s, Self::int_nbits(), Self::frac_nbits()).map(Self::from_bits)
|
||||
$method(s, Self::int_nbits(), Self::frac_nbits()).map(Self::from_bits)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<Frac> FromStr for FixedU8<Frac>
|
||||
where
|
||||
Frac: Unsigned + IsLessOrEqual<U8, Output = True>,
|
||||
{
|
||||
type Err = ParseFixedError;
|
||||
#[inline]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
from_str_u8(s, Self::int_nbits(), Self::frac_nbits()).map(Self::from_bits)
|
||||
}
|
||||
}
|
||||
macro_rules! impl_from_str_signed {
|
||||
(
|
||||
($Fixed:ident, $NBits:ident, $Bits:ident, $DoubleBits:ident, $one:expr);
|
||||
fn $all:ident;
|
||||
fn $int:ident;
|
||||
$frac:ident;
|
||||
) => {
|
||||
impl_from_str! { $Fixed, $NBits, $all }
|
||||
|
||||
fn from_str_i8(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<i8, ParseFixedError> {
|
||||
fn $all(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<$Bits, ParseFixedError> {
|
||||
let Parse { neg, int, frac } = parse(s, true)?;
|
||||
let (frac, whole_frac) = match get_frac8(frac, frac_nbits) {
|
||||
let (frac, whole_frac) = match $frac(frac, frac_nbits) {
|
||||
Some(frac) => (frac, false),
|
||||
None => (0, true),
|
||||
};
|
||||
let frac = if frac_nbits == 8 {
|
||||
let frac = if frac_nbits == <$Bits>::NBITS {
|
||||
// special case: no int bits
|
||||
if neg {
|
||||
if frac > 0x80 {
|
||||
if frac > <$Bits as SealedInt>::Unsigned::MSB {
|
||||
err!(Overflow)
|
||||
}
|
||||
frac.wrapping_neg() as i8
|
||||
frac.wrapping_neg() as $Bits
|
||||
} else {
|
||||
if frac >= 0x80 {
|
||||
if frac >= <$Bits as SealedInt>::Unsigned::MSB {
|
||||
err!(Overflow)
|
||||
}
|
||||
frac as i8
|
||||
frac as $Bits
|
||||
}
|
||||
} else {
|
||||
frac as i8
|
||||
frac as $Bits
|
||||
};
|
||||
let int = get_int_i8(neg, int, int_nbits, whole_frac)?;
|
||||
let int = $int(neg, int, int_nbits, whole_frac)?;
|
||||
Ok(int | frac)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_str_u8(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<u8, ParseFixedError> {
|
||||
let Parse { neg: _, int, frac } = parse(s, false)?;
|
||||
let (frac, whole_frac) = match get_frac8(frac, frac_nbits) {
|
||||
Some(frac) => (frac, false),
|
||||
None => (0, true),
|
||||
};
|
||||
let int = get_int_u8(int, int_nbits, whole_frac)?;
|
||||
Ok(int | frac)
|
||||
}
|
||||
|
||||
fn get_int_i8(neg: bool, int: &[u8], nbits: u32, whole_frac: bool) -> Result<i8, ParseFixedError> {
|
||||
fn $int(
|
||||
neg: bool,
|
||||
int: &[u8],
|
||||
nbits: u32,
|
||||
whole_frac: bool,
|
||||
) -> Result<$Bits, ParseFixedError> {
|
||||
let mut int = int;
|
||||
while !int.is_empty() && int[0] == b'0' {
|
||||
int = &int[1..];
|
||||
|
@ -316,13 +313,13 @@ fn get_int_i8(neg: bool, int: &[u8], nbits: u32, whole_frac: bool) -> Result<i8,
|
|||
return Ok(0);
|
||||
}
|
||||
let max_abs_int = if neg {
|
||||
1u16 << (nbits - 1)
|
||||
$one << (nbits - 1)
|
||||
} else {
|
||||
(1u16 << (nbits - 1)) - 1
|
||||
($one << (nbits - 1)) - 1
|
||||
};
|
||||
let mut acc = 0;
|
||||
for &c in int {
|
||||
acc = acc * 10 + (c - b'0') as u16;
|
||||
acc = acc * 10 + (c - b'0') as $DoubleBits;
|
||||
err!(acc > max_abs_int, Overflow);
|
||||
}
|
||||
if whole_frac {
|
||||
|
@ -330,14 +327,36 @@ fn get_int_i8(neg: bool, int: &[u8], nbits: u32, whole_frac: bool) -> Result<i8,
|
|||
err!(acc > max_abs_int, Overflow);
|
||||
}
|
||||
let signed = if neg {
|
||||
acc.wrapping_neg() as i8
|
||||
acc.wrapping_neg() as $Bits
|
||||
} else {
|
||||
acc as i8
|
||||
acc as $Bits
|
||||
};
|
||||
Ok(signed << (<$Bits>::NBITS - nbits))
|
||||
}
|
||||
};
|
||||
Ok(signed << (8 - nbits))
|
||||
}
|
||||
|
||||
fn get_int_u8(int: &[u8], nbits: u32, whole_frac: bool) -> Result<u8, ParseFixedError> {
|
||||
macro_rules! impl_from_str_unsigned {
|
||||
(
|
||||
($Fixed:ident, $NBits:ident, $Bits:ident, $DoubleBits:ident, $one:expr);
|
||||
fn $all:ident;
|
||||
fn $int:ident;
|
||||
fn $frac:ident;
|
||||
$decode_frac:ident, $dec_frac_digits:expr;
|
||||
) => {
|
||||
impl_from_str! { $Fixed, $NBits, $all }
|
||||
|
||||
fn $all(s: &str, int_nbits: u32, frac_nbits: u32) -> Result<$Bits, ParseFixedError> {
|
||||
let Parse { neg: _, int, frac } = parse(s, false)?;
|
||||
let (frac, whole_frac) = match $frac(frac, frac_nbits) {
|
||||
Some(frac) => (frac, false),
|
||||
None => (0, true),
|
||||
};
|
||||
let int = $int(int, int_nbits, whole_frac)?;
|
||||
Ok(int | frac)
|
||||
}
|
||||
|
||||
fn $int(int: &[u8], nbits: u32, whole_frac: bool) -> Result<$Bits, ParseFixedError> {
|
||||
let mut int = int;
|
||||
while !int.is_empty() && int[0] == b'0' {
|
||||
int = &int[1..];
|
||||
|
@ -346,37 +365,66 @@ fn get_int_u8(int: &[u8], nbits: u32, whole_frac: bool) -> Result<u8, ParseFixed
|
|||
err!(whole_frac || !int.is_empty(), Overflow);
|
||||
return Ok(0);
|
||||
}
|
||||
let max_abs_int = (1u16 << nbits) - 1;
|
||||
let max_abs_int = ($one << nbits) - 1;
|
||||
let mut acc = 0;
|
||||
for &c in int {
|
||||
acc = acc * 10 + (c - b'0') as u16;
|
||||
acc = acc * 10 + (c - b'0') as $DoubleBits;
|
||||
err!(acc > max_abs_int, Overflow);
|
||||
}
|
||||
if whole_frac {
|
||||
acc += 1;
|
||||
err!(acc > max_abs_int, Overflow);
|
||||
}
|
||||
Ok((acc as u8) << (8 - nbits))
|
||||
}
|
||||
Ok((acc as $Bits) << (<$Bits as SealedInt>::NBITS - nbits))
|
||||
}
|
||||
|
||||
fn get_frac8(frac: &[u8], nbits: u32) -> Option<u8> {
|
||||
fn $frac(frac: &[u8], nbits: u32) -> Option<$Bits> {
|
||||
if frac.is_empty() {
|
||||
return Some(0);
|
||||
}
|
||||
let mut digits = display::dec_frac_digits(8);
|
||||
debug_assert!(digits <= 3);
|
||||
let mut digits = $dec_frac_digits;
|
||||
let mut acc = 0;
|
||||
for &c in frac {
|
||||
if digits == 0 {
|
||||
break;
|
||||
}
|
||||
digits -= 1;
|
||||
acc = acc * 10 + (c - b'0') as u16;
|
||||
acc = acc * 10 + (c - b'0') as $DoubleBits;
|
||||
}
|
||||
for _ in 0..digits {
|
||||
acc *= 10;
|
||||
}
|
||||
dec3_to_bin8(acc, 8 - nbits)
|
||||
$decode_frac(acc, <$Bits as SealedInt>::NBITS - nbits)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_from_str_signed! {
|
||||
(FixedI8, U8, i8, u16, 1u16);
|
||||
fn from_str_i8;
|
||||
fn get_int_i8;
|
||||
get_frac8;
|
||||
}
|
||||
impl_from_str_unsigned! {
|
||||
(FixedU8, U8, u8, u16, 1u16);
|
||||
fn from_str_u8;
|
||||
fn get_int_u8;
|
||||
fn get_frac8;
|
||||
dec3_to_bin8, 3;
|
||||
}
|
||||
|
||||
impl_from_str_signed! {
|
||||
(FixedI16, U16, i16, u32, 1u32);
|
||||
fn from_str_i16;
|
||||
fn get_int_i16;
|
||||
get_frac16;
|
||||
}
|
||||
impl_from_str_unsigned! {
|
||||
(FixedU16, U16, u16, u32, 1u32);
|
||||
fn from_str_u16;
|
||||
fn get_int_u16;
|
||||
fn get_frac16;
|
||||
dec6_to_bin16, 6;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -523,7 +571,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn check_i8_from_str() {
|
||||
fn check_i8_u8_from_str() {
|
||||
use crate::types::*;
|
||||
|
||||
assert_eq!("0.498".parse::<I0F8>().unwrap(), I0F8::from_bits(127));
|
||||
|
@ -545,11 +593,6 @@ mod tests {
|
|||
assert_eq!("-128.499".parse::<I8F0>().unwrap(), I8F0::from_bits(-128));
|
||||
let ParseFixedError { kind } = "-128.5".parse::<I8F0>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_u8_from_str() {
|
||||
use crate::types::*;
|
||||
|
||||
assert_eq!("0.498".parse::<U0F8>().unwrap(), U0F8::from_bits(127));
|
||||
assert_eq!("0.499".parse::<U0F8>().unwrap(), U0F8::from_bits(128));
|
||||
|
@ -568,4 +611,76 @@ mod tests {
|
|||
let ParseFixedError { kind } = "255.5".parse::<U8F0>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_i16_u16_from_str() {
|
||||
use crate::types::*;
|
||||
|
||||
assert_eq!(
|
||||
"0.499992".parse::<I0F16>().unwrap(),
|
||||
I0F16::from_bits(32767)
|
||||
);
|
||||
let ParseFixedError { kind } = "0.499993".parse::<I0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
let ParseFixedError { kind } = "1".parse::<I0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
|
||||
assert_eq!(
|
||||
"-0.500007".parse::<I0F16>().unwrap(),
|
||||
I0F16::from_bits(-32768)
|
||||
);
|
||||
let ParseFixedError { kind } = "-0.500008".parse::<I0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
let ParseFixedError { kind } = "-1".parse::<I0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
|
||||
assert_eq!(
|
||||
"00032767.499999".parse::<I16F0>().unwrap(),
|
||||
I16F0::from_bits(32767)
|
||||
);
|
||||
let ParseFixedError { kind } = "32767.5".parse::<I16F0>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
|
||||
assert_eq!(
|
||||
"-32768.499999".parse::<I16F0>().unwrap(),
|
||||
I16F0::from_bits(-32768)
|
||||
);
|
||||
let ParseFixedError { kind } = "-32768.5".parse::<I16F0>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
|
||||
assert_eq!(
|
||||
"0.499992".parse::<U0F16>().unwrap(),
|
||||
U0F16::from_bits(32767)
|
||||
);
|
||||
assert_eq!(
|
||||
"0.499993".parse::<U0F16>().unwrap(),
|
||||
U0F16::from_bits(32768)
|
||||
);
|
||||
assert_eq!(
|
||||
"0.999992".parse::<U0F16>().unwrap(),
|
||||
U0F16::from_bits(65535)
|
||||
);
|
||||
let ParseFixedError { kind } = "0.999993".parse::<U0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
let ParseFixedError { kind } = "1".parse::<U0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
|
||||
let ParseFixedError { kind } = "-0".parse::<U0F16>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::InvalidDigit);
|
||||
|
||||
assert_eq!(
|
||||
"00032767.499999".parse::<U16F0>().unwrap(),
|
||||
U16F0::from_bits(32767)
|
||||
);
|
||||
assert_eq!(
|
||||
"00032767.5".parse::<U16F0>().unwrap(),
|
||||
U16F0::from_bits(32768)
|
||||
);
|
||||
assert_eq!(
|
||||
"65535.499999".parse::<U16F0>().unwrap(),
|
||||
U16F0::from_bits(65535)
|
||||
);
|
||||
let ParseFixedError { kind } = "65535.5".parse::<U16F0>().unwrap_err();
|
||||
assert_eq!(kind, ParseErrorKind::Overflow);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue