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