ibig/parse/mod.rs
1//! Parsing numbers.
2
3use crate::{
4 error::ParseError,
5 ibig::IBig,
6 radix::{self, Digit},
7 sign::Sign::*,
8 ubig::UBig,
9};
10use core::str::FromStr;
11
12mod non_power_two;
13mod power_two;
14
15impl FromStr for UBig {
16 type Err = ParseError;
17
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
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 /// # Panics
38 ///
39 /// Panics if `radix` is not between 2 and 36 inclusive.
40 ///
41 /// # Examples
42 /// ```
43 /// # use ibig::{error::ParseError, ubig, UBig};
44 /// assert_eq!(UBig::from_str_radix("+7ab", 32)?, ubig!(7499));
45 /// # Ok::<(), ParseError>(())
46 /// ```
47 pub fn from_str_radix(src: &str, radix: u32) -> Result<UBig, ParseError> {
48 radix::check_radix_valid(radix);
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].
54 ///
55 /// `src` may contain an optional `+` after the radix prefix.
56 ///
57 /// Allowed prefixes: `0b` for binary, `0o` for octal, `0x` for hexadecimal.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// # use ibig::{error::ParseError, ubig, UBig};
63 /// assert_eq!(UBig::from_str_with_radix_prefix("+0o17")?, ubig!(0o17));
64 /// assert_eq!(UBig::from_str_with_radix_prefix("0x1f")?, ubig!(0x1f));
65 /// # Ok::<(), ParseError>(())
66 /// ```
67 pub fn from_str_with_radix_prefix(src: &str) -> Result<UBig, ParseError> {
68 let src = src.strip_prefix('+').unwrap_or(src);
69 UBig::from_str_with_radix_prefix_no_sign(src)
70 }
71
72 /// Convert an unsigned string with an optional radix prefix to [UBig].
73 fn from_str_with_radix_prefix_no_sign(src: &str) -> Result<UBig, ParseError> {
74 if let Some(bin) = src.strip_prefix("0b") {
75 UBig::from_str_radix_no_sign(bin, 2)
76 } else if let Some(oct) = src.strip_prefix("0o") {
77 UBig::from_str_radix_no_sign(oct, 8)
78 } else if let Some(hex) = src.strip_prefix("0x") {
79 UBig::from_str_radix_no_sign(hex, 16)
80 } else {
81 UBig::from_str_radix_no_sign(src, 10)
82 }
83 }
84
85 /// Convert an unsigned string to [UBig].
86 fn from_str_radix_no_sign(mut src: &str, radix: Digit) -> Result<UBig, ParseError> {
87 debug_assert!(radix::is_radix_valid(radix));
88 if src.is_empty() {
89 return Err(ParseError::NoDigits);
90 }
91
92 while let Some(src2) = src.strip_prefix('0') {
93 src = src2;
94 }
95
96 if radix.is_power_of_two() {
97 power_two::parse(src, radix)
98 } else {
99 non_power_two::parse(src, radix)
100 }
101 }
102}
103
104impl IBig {
105 /// Convert a string in a given base to [IBig].
106 ///
107 /// The string may contain a `+` or `-` prefix.
108 /// Digits 10-35 are represented by `a-z` or `A-Z`.
109 ///
110 /// # Panics
111 ///
112 /// Panics if `radix` is not between 2 and 36 inclusive.
113 ///
114 /// # Examples
115 /// ```
116 /// # use ibig::{error::ParseError, ibig, IBig};
117 /// assert_eq!(IBig::from_str_radix("-7ab", 32)?, ibig!(-7499));
118 /// # Ok::<(), ParseError>(())
119 /// ```
120 pub fn from_str_radix(mut src: &str, radix: u32) -> Result<IBig, ParseError> {
121 radix::check_radix_valid(radix);
122 let sign;
123 match src.strip_prefix('-') {
124 Some(s) => {
125 sign = Negative;
126 src = s;
127 }
128 None => {
129 sign = Positive;
130 src = src.strip_prefix('+').unwrap_or(src);
131 }
132 }
133 let mag = UBig::from_str_radix_no_sign(src, radix)?;
134 Ok(IBig::from_sign_magnitude(sign, mag))
135 }
136
137 /// Convert a string with an optional radix prefix to [IBig].
138 ///
139 /// `src` may contain an '+' or `-` prefix after the radix prefix.
140 ///
141 /// Allowed prefixes: `0b` for binary, `0o` for octal, `0x` for hexadecimal.
142 ///
143 /// # Examples
144 /// ```
145 /// # use ibig::{error::ParseError, ibig, IBig};
146 /// assert_eq!(IBig::from_str_with_radix_prefix("+0o17")?, ibig!(0o17));
147 /// assert_eq!(IBig::from_str_with_radix_prefix("-0x1f")?, ibig!(-0x1f));
148 /// # Ok::<(), ParseError>(())
149 /// ```
150 pub fn from_str_with_radix_prefix(mut src: &str) -> Result<IBig, ParseError> {
151 let sign;
152 match src.strip_prefix('-') {
153 Some(s) => {
154 sign = Negative;
155 src = s;
156 }
157 None => {
158 sign = Positive;
159 src = src.strip_prefix('+').unwrap_or(src);
160 }
161 }
162 let mag = UBig::from_str_with_radix_prefix_no_sign(src)?;
163 Ok(IBig::from_sign_magnitude(sign, mag))
164 }
165}