ethnum/int/
parse.rs

1//! Module implementing parsing for `I256` type.
2
3use crate::int::I256;
4
5impl_from_str! {
6    impl FromStr for I256;
7}
8
9pub const fn const_from_str_prefixed(src: &str) -> I256 {
10    assert!(!src.is_empty(), "empty string");
11
12    let bytes = src.as_bytes();
13    let (negate, start) = match bytes[0] {
14        b'+' => (false, 1),
15        b'-' => (true, 1),
16        _ => (false, 0),
17    };
18    let uint = crate::parse::const_from_str_prefixed(bytes, start as _);
19
20    let int = {
21        let (hi, lo) = if negate {
22            let (hi, lo) = uint.into_words();
23            let (lo, carry) = (!lo).overflowing_add(1);
24            let hi = (!hi).wrapping_add(carry as _);
25            (hi, lo)
26        } else {
27            uint.into_words()
28        };
29        I256::from_words(hi as _, lo as _)
30    };
31
32    if matches!((negate, int.signum128()), (false, -1) | (true, 1)) {
33        panic!("overflows integer type");
34    }
35
36    int
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42    use crate::parse::from_str_radix;
43    use core::num::IntErrorKind;
44
45    #[test]
46    fn from_str() {
47        assert_eq!("42".parse::<I256>().unwrap(), 42);
48    }
49
50    #[test]
51    fn from_str_prefixed() {
52        assert_eq!(from_str_radix::<I256>("0b101", 2, Some("0b")).unwrap(), 5);
53        assert_eq!(from_str_radix::<I256>("-0xf", 16, Some("0x")).unwrap(), -15);
54    }
55
56    #[test]
57    fn from_str_errors() {
58        assert_eq!(
59            from_str_radix::<I256>("", 2, None).unwrap_err().kind(),
60            &IntErrorKind::Empty,
61        );
62        assert_eq!(
63            from_str_radix::<I256>("?", 2, None).unwrap_err().kind(),
64            &IntErrorKind::InvalidDigit,
65        );
66        assert_eq!(
67            from_str_radix::<I256>("1", 16, Some("0x"))
68                .unwrap_err()
69                .kind(),
70            &IntErrorKind::InvalidDigit,
71        );
72        assert_eq!(
73            from_str_radix::<I256>(
74                "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
75                36,
76                None
77            )
78            .unwrap_err()
79            .kind(),
80            &IntErrorKind::PosOverflow,
81        );
82        assert_eq!(
83            from_str_radix::<I256>(
84                "-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
85                36,
86                None
87            )
88            .unwrap_err()
89            .kind(),
90            &IntErrorKind::NegOverflow,
91        );
92    }
93
94    #[test]
95    fn const_parse() {
96        assert_eq!(const_from_str_prefixed("-0b1101"), -0b1101);
97        assert_eq!(const_from_str_prefixed("0o777"), 0o777);
98        assert_eq!(const_from_str_prefixed("-0x1f"), -0x1f);
99        assert_eq!(const_from_str_prefixed("+42"), 42);
100
101        assert_eq!(
102            const_from_str_prefixed(
103                "0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_fffe\
104                   baae_dce6_af48_a03b_bfd2_5e8c_d036_4141"
105            ),
106            I256::from_words(
107                0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_fffe,
108                0xbaae_dce6_af48_a03b_bfd2_5e8c_d036_4141_u128 as _,
109            ),
110        );
111
112        assert_eq!(
113            const_from_str_prefixed(
114                "-0x8000_0000_0000_0000_0000_0000_0000_0000\
115                    0000_0000_0000_0000_0000_0000_0000_0000"
116            ),
117            I256::MIN,
118        );
119        assert_eq!(
120            const_from_str_prefixed(
121                "+0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff\
122                    ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff"
123            ),
124            I256::MAX,
125        );
126    }
127
128    #[test]
129    #[should_panic]
130    fn const_parse_overflow() {
131        const_from_str_prefixed(
132            "0x8000_0000_0000_0000_0000_0000_0000_0000\
133               0000_0000_0000_0000_0000_0000_0000_0000",
134        );
135    }
136
137    #[test]
138    #[should_panic]
139    fn const_parse_negative_overflow() {
140        const_from_str_prefixed(
141            "-0x8000_0000_0000_0000_0000_0000_0000_0000\
142                0000_0000_0000_0000_0000_0000_0000_0001",
143        );
144    }
145
146    #[test]
147    #[should_panic]
148    fn const_parse_invalid() {
149        const_from_str_prefixed("invalid");
150    }
151}