malachite_nz/integer/conversion/string/from_string.rs
1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::integer::Integer;
10use crate::natural::Natural;
11use core::ops::Neg;
12use core::str::FromStr;
13use malachite_base::num::conversion::traits::FromStringBase;
14
15impl FromStr for Integer {
16 type Err = ();
17
18 /// Converts an string to an [`Integer`].
19 ///
20 /// If the string does not represent a valid [`Integer`], an `Err` is returned. To be valid, the
21 /// string must be nonempty and only contain the [`char`]s `'0'` through `'9'`, with an optional
22 /// leading `'-'`. Leading zeros are allowed, as is the string `"-0"`. The string `"-"` is not.
23 ///
24 /// # Worst-case complexity
25 /// $T(n) = O(n (\log n)^2 \log\log n)$
26 ///
27 /// $M(n) = O(n \log n)$
28 ///
29 /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
30 ///
31 /// # Examples
32 /// ```
33 /// use core::str::FromStr;
34 /// use malachite_nz::integer::Integer;
35 ///
36 /// assert_eq!(Integer::from_str("123456").unwrap(), 123456);
37 /// assert_eq!(Integer::from_str("00123456").unwrap(), 123456);
38 /// assert_eq!(Integer::from_str("0").unwrap(), 0);
39 /// assert_eq!(Integer::from_str("-123456").unwrap(), -123456);
40 /// assert_eq!(Integer::from_str("-00123456").unwrap(), -123456);
41 /// assert_eq!(Integer::from_str("-0").unwrap(), 0);
42 ///
43 /// assert!(Integer::from_str("").is_err());
44 /// assert!(Integer::from_str("a").is_err());
45 /// ```
46 #[inline]
47 fn from_str(s: &str) -> Result<Integer, ()> {
48 Integer::from_string_base(10, s).ok_or(())
49 }
50}
51
52impl FromStringBase for Integer {
53 /// Converts an string, in a specified base, to an [`Integer`].
54 ///
55 /// If the string does not represent a valid [`Integer`], an `Err` is returned. To be valid, the
56 /// string must be nonempty and only contain the [`char`]s `'0'` through `'9'`, `'a'` through
57 /// `'z'`, and `'A'` through `'Z'`, with an optional single leading `'-'` or `'+'`; and only
58 /// characters that represent digits smaller than the base are allowed. Leading zeros are
59 /// allowed, as is the string `"-0"`. The string `"-"` is not.
60 ///
61 /// # Worst-case complexity
62 /// $T(n) = O(n (\log n)^2 \log\log n)$
63 ///
64 /// $M(n) = O(n \log n)$
65 ///
66 /// where $T$ is time, $M$ is additional memory, and $n$ is `s.len()`.
67 ///
68 /// # Panics
69 /// Panics if `base` is less than 2 or greater than 36.
70 ///
71 /// # Examples
72 /// ```
73 /// use malachite_base::num::conversion::traits::FromStringBase;
74 /// use malachite_nz::integer::Integer;
75 ///
76 /// assert_eq!(Integer::from_string_base(10, "123456").unwrap(), 123456);
77 /// assert_eq!(Integer::from_string_base(10, "00123456").unwrap(), 123456);
78 /// assert_eq!(Integer::from_string_base(16, "0").unwrap(), 0);
79 /// assert_eq!(
80 /// Integer::from_string_base(16, "deadbeef").unwrap(),
81 /// 3735928559i64
82 /// );
83 /// assert_eq!(
84 /// Integer::from_string_base(16, "deAdBeEf").unwrap(),
85 /// 3735928559i64
86 /// );
87 /// assert_eq!(Integer::from_string_base(10, "-123456").unwrap(), -123456);
88 /// assert_eq!(Integer::from_string_base(10, "-00123456").unwrap(), -123456);
89 /// assert_eq!(Integer::from_string_base(16, "-0").unwrap(), 0);
90 /// assert_eq!(
91 /// Integer::from_string_base(16, "-deadbeef").unwrap(),
92 /// -3735928559i64
93 /// );
94 /// assert_eq!(
95 /// Integer::from_string_base(16, "-deAdBeEf").unwrap(),
96 /// -3735928559i64
97 /// );
98 ///
99 /// assert!(Integer::from_string_base(10, "").is_none());
100 /// assert!(Integer::from_string_base(10, "a").is_none());
101 /// assert!(Integer::from_string_base(2, "2").is_none());
102 /// assert!(Integer::from_string_base(2, "-2").is_none());
103 /// ```
104 #[inline]
105 fn from_string_base(base: u8, s: &str) -> Option<Integer> {
106 if let Some(abs_string) = s.strip_prefix('-') {
107 if abs_string.starts_with('+') {
108 None
109 } else {
110 Natural::from_string_base(base, abs_string).map(Neg::neg)
111 }
112 } else {
113 Natural::from_string_base(base, s).map(Integer::from)
114 }
115 }
116}