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}