dashu_int/parse/mod.rs
1//! Integer parsing helpers.
2
3use crate::{
4 ibig::IBig,
5 radix::{self, is_radix_valid, Digit},
6 ubig::UBig,
7 Sign::*,
8};
9use core::str::FromStr;
10use dashu_base::ParseError;
11
12mod non_power_two;
13mod power_two;
14
15impl FromStr for UBig {
16 type Err = ParseError;
17 #[inline]
18 fn from_str(s: &str) -> Result<UBig, ParseError> {
19 UBig::from_str_radix(s, 10)
20 }
21}
22
23impl FromStr for IBig {
24 type Err = ParseError;
25 #[inline]
26 fn from_str(s: &str) -> Result<IBig, ParseError> {
27 IBig::from_str_radix(s, 10)
28 }
29}
30
31impl UBig {
32 /// Convert a string in a given base to [UBig].
33 ///
34 /// `src` may contain an optional `+` prefix.
35 /// Digits 10-35 are represented by `a-z` or `A-Z`.
36 ///
37 /// # Examples
38 /// ```
39 /// # use dashu_base::ParseError;
40 /// # use dashu_int::UBig;
41 /// assert_eq!(UBig::from_str_radix("+7ab", 32)?, UBig::from(7499u16));
42 /// # Ok::<(), ParseError>(())
43 /// ```
44 pub fn from_str_radix(src: &str, radix: u32) -> Result<UBig, ParseError> {
45 let radix = u8::try_from(radix).map_err(|_| ParseError::UnsupportedRadix)?;
46 if !is_radix_valid(radix) {
47 return Err(ParseError::UnsupportedRadix);
48 }
49 let src = src.strip_prefix('+').unwrap_or(src);
50 UBig::from_str_radix_no_sign(src, radix)
51 }
52
53 /// Convert a string with an optional radix prefix to [UBig], returns the
54 /// parsed integer and radix.
55 ///
56 /// It's equivalent to [UBig::from_str_with_radix_default] with 10 as the default radix.
57 #[inline]
58 pub fn from_str_with_radix_prefix(src: &str) -> Result<(UBig, Digit), ParseError> {
59 UBig::from_str_with_radix_default(src, 10)
60 }
61
62 /// Convert a string with an optional radix prefix to [UBig], returns the
63 /// parsed integer and radix. If no prefix is present, then the default radix input
64 /// will be used for parsing.
65 ///
66 /// `src` may contain an optional `+` before the radix prefix.
67 ///
68 /// Allowed prefixes: `0b` for binary, `0o` for octal, `0x` for hexadecimal.
69 ///
70 /// # Examples
71 ///
72 /// ```
73 /// # use dashu_base::ParseError;
74 /// # use dashu_int::UBig;
75 /// assert_eq!(UBig::from_str_with_radix_default("+0o17", 10)?, (UBig::from(0o17u8), 8));
76 /// assert_eq!(UBig::from_str_with_radix_default("0x1f", 10)?.0, UBig::from(0x1fu8));
77 /// # Ok::<(), ParseError>(())
78 /// ```
79 #[inline]
80 pub fn from_str_with_radix_default(
81 src: &str,
82 default_radix: Digit,
83 ) -> Result<(UBig, Digit), ParseError> {
84 let src = src.strip_prefix('+').unwrap_or(src);
85 UBig::from_str_with_radix_prefix_no_sign(src, default_radix)
86 }
87
88 /// Convert an unsigned string with an optional radix prefix to [UBig].
89 fn from_str_with_radix_prefix_no_sign(
90 src: &str,
91 default_radix: Digit,
92 ) -> Result<(UBig, Digit), ParseError> {
93 if let Some(bin) = src.strip_prefix("0b") {
94 UBig::from_str_radix_no_sign(bin, 2).map(|v| (v, 2))
95 } else if let Some(oct) = src.strip_prefix("0o") {
96 UBig::from_str_radix_no_sign(oct, 8).map(|v| (v, 8))
97 } else if let Some(hex) = src.strip_prefix("0x") {
98 UBig::from_str_radix_no_sign(hex, 16).map(|v| (v, 16))
99 } else {
100 UBig::from_str_radix_no_sign(src, default_radix).map(|v| (v, default_radix))
101 }
102 }
103
104 /// Convert an unsigned string to [UBig].
105 fn from_str_radix_no_sign(mut src: &str, radix: Digit) -> Result<UBig, ParseError> {
106 debug_assert!(radix::is_radix_valid(radix));
107 if src.is_empty() {
108 return Err(ParseError::NoDigits);
109 }
110
111 while let Some(src2) = src.strip_prefix('0') {
112 src = src2;
113 }
114
115 if radix.is_power_of_two() {
116 power_two::parse(src, radix)
117 } else {
118 non_power_two::parse(src, radix)
119 }
120 }
121}
122
123impl IBig {
124 /// Convert a string in a given base to [IBig].
125 ///
126 /// The string may contain a `+` or `-` prefix.
127 /// Digits 10-35 are represented by `a-z` or `A-Z`.
128 ///
129 /// # Examples
130 /// ```
131 /// # use dashu_base::ParseError;
132 /// # use dashu_int::IBig;
133 /// assert_eq!(IBig::from_str_radix("-7ab", 32)?, IBig::from(-7499));
134 /// # Ok::<(), ParseError>(())
135 /// ```
136 pub fn from_str_radix(mut src: &str, radix: u32) -> Result<IBig, ParseError> {
137 let radix = u8::try_from(radix).map_err(|_| ParseError::UnsupportedRadix)?;
138 if !is_radix_valid(radix) {
139 return Err(ParseError::UnsupportedRadix);
140 }
141
142 let sign = match src.strip_prefix('-') {
143 Some(s) => {
144 src = s;
145 Negative
146 }
147 None => {
148 src = src.strip_prefix('+').unwrap_or(src);
149 Positive
150 }
151 };
152 let mag = UBig::from_str_radix_no_sign(src, radix)?;
153 Ok(IBig(mag.0.with_sign(sign)))
154 }
155
156 /// Convert a string with an optional radix prefix to [IBig], return the
157 /// parsed integer and radix.
158 ///
159 /// It's equivalent to [IBig::from_str_with_radix_default] with 10 as the default radix.
160 pub fn from_str_with_radix_prefix(src: &str) -> Result<(IBig, Digit), ParseError> {
161 IBig::from_str_with_radix_default(src, 10)
162 }
163
164 /// Convert a string with an optional radix prefix to [IBig], return the
165 /// parsed integer and radix. If no prefix is present, then the default radix input
166 /// will be used for parsing.
167 ///
168 /// `src` may contain an '+' or `-` prefix before the radix prefix.
169 ///
170 /// Allowed prefixes: `0b` for binary, `0o` for octal, `0x` for hexadecimal.
171 ///
172 /// # Examples
173 /// ```
174 /// # use dashu_base::ParseError;
175 /// # use dashu_int::IBig;
176 /// assert_eq!(IBig::from_str_with_radix_default("+0o17", 10)?, (IBig::from(0o17), 8));
177 /// assert_eq!(IBig::from_str_with_radix_default("-0x1f", 10)?.0, IBig::from(-0x1f));
178 /// # Ok::<(), ParseError>(())
179 /// ```
180 #[inline]
181 pub fn from_str_with_radix_default(
182 src: &str,
183 default_radix: Digit,
184 ) -> Result<(IBig, Digit), ParseError> {
185 let (src, sign) = match src.strip_prefix('-') {
186 Some(s) => (s, Negative),
187 None => (src.strip_prefix('+').unwrap_or(src), Positive),
188 };
189 let (mag, radix) = UBig::from_str_with_radix_prefix_no_sign(src, default_radix)?;
190 Ok((IBig(mag.0.with_sign(sign)), radix))
191 }
192}