1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
use crate::{
rbig::{RBig, Relaxed},
repr::Repr,
};
use core::str::FromStr;
use dashu_base::ParseError;
use dashu_int::{IBig, UBig};
impl Repr {
fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseError> {
if let Some(slash) = src.find('/') {
let num = IBig::from_str_radix(&src[..slash], radix)?;
let den = IBig::from_str_radix(&src[slash + 1..], radix)?;
let (sign, den) = den.into_parts();
Ok(Repr {
numerator: num * sign,
denominator: den,
})
} else {
let n = IBig::from_str_radix(src, radix)?;
Ok(Repr {
numerator: n,
denominator: UBig::ONE,
})
}
}
pub fn from_str_with_radix_prefix(src: &str) -> Result<(Self, u32), ParseError> {
if let Some(slash) = src.find('/') {
// first parse the numerator part
let (num, num_radix) = IBig::from_str_with_radix_prefix(&src[..slash])?;
let (den, den_radix) = IBig::from_str_with_radix_default(&src[slash + 1..], num_radix)?;
let (den_sign, den) = den.into_parts();
if num_radix != den_radix {
return Err(ParseError::InconsistentRadix);
}
Ok((
Repr {
numerator: num * den_sign,
denominator: den,
},
num_radix,
))
} else {
let (n, radix) = IBig::from_str_with_radix_prefix(src)?;
Ok((
Repr {
numerator: n,
denominator: UBig::ONE,
},
radix,
))
}
}
}
impl RBig {
/// Convert a string in a given base to [RBig].
///
/// The numerator and the denominator are separated by `/`.
/// `src` may contain an optional `+` prefix.
/// Digits 10-35 are represented by `a-z` or `A-Z`.
///
/// # Examples
/// ```
/// # use dashu_base::ParseError;
/// # use dashu_ratio::RBig;
/// assert_eq!(
/// RBig::from_str_radix("+7ab/-sse", 32)?,
/// RBig::from_parts((-7499).into(), 29582u16.into())
/// );
/// # Ok::<(), ParseError>(())
/// ```
#[inline]
pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseError> {
Repr::from_str_radix(src, radix).map(|repr| RBig(repr.reduce()))
}
/// Convert a string with optional radix prefixes to [RBig], return the
/// parsed integer and radix. If no prefix is present, then the default radix 10
/// will be used for parsing.
///
/// `src` may contain an '+' or `-` prefix before the radix prefix of both the
/// numerator and denominator.
///
/// Allowed prefixes: `0b` for binary, `0o` for octal, `0x` for hexadecimal.
///
/// If the radix prefixes for the numerator and the denominator are not the same,
/// then a ParseError will be returned. The radix prefix for the denominator can be
/// omitted, and the radix for the numerator will used for parsing.
///
/// # Examples
/// ```
/// # use dashu_base::ParseError;
/// # use dashu_ratio::RBig;
/// assert_eq!(RBig::from_str_with_radix_prefix("+0o17/25")?,
/// (RBig::from_parts(0o17.into(), 0o25u8.into()), 8));
/// assert_eq!(RBig::from_str_with_radix_prefix("-0x1f/-0x1e")?,
/// (RBig::from_parts(0x1f.into(), 0x1eu8.into()), 16));
/// # Ok::<(), ParseError>(())
/// ```
#[inline]
pub fn from_str_with_radix_prefix(src: &str) -> Result<(Self, u32), ParseError> {
Repr::from_str_with_radix_prefix(src).map(|(repr, radix)| (Self(repr.reduce()), radix))
}
}
impl FromStr for RBig {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, ParseError> {
Self::from_str_radix(s, 10)
}
}
impl Relaxed {
/// Convert a string in a given base to [Relaxed].
///
/// See [RBig::from_str_radix] for details.
#[inline]
pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseError> {
Repr::from_str_radix(src, radix).map(|repr| Relaxed(repr.reduce2()))
}
/// Convert a string with optional radix prefixes to [RBig], return the
/// parsed integer and radix.
///
/// See [RBig::from_str_with_radix_prefix] for details.
#[inline]
pub fn from_str_with_radix_prefix(src: &str) -> Result<(Self, u32), ParseError> {
Repr::from_str_with_radix_prefix(src).map(|(repr, radix)| (Self(repr.reduce2()), radix))
}
}
impl FromStr for Relaxed {
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<Self, ParseError> {
Self::from_str_radix(s, 10)
}
}