Skip to main content

core/num/
error.rs

1//! Error types for conversion to integral types.
2
3use crate::convert::Infallible;
4#[cfg(not(feature = "ferrocene_subset"))]
5use crate::error::Error;
6use crate::fmt;
7
8/// The error type returned when a checked integral type conversion fails.
9#[stable(feature = "try_from", since = "1.34.0")]
10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
11pub struct TryFromIntError(pub(crate) ());
12
13#[stable(feature = "try_from", since = "1.34.0")]
14impl fmt::Display for TryFromIntError {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        "out of range integral type conversion attempted".fmt(f)
17    }
18}
19
20#[stable(feature = "try_from", since = "1.34.0")]
21#[cfg(not(feature = "ferrocene_subset"))]
22impl Error for TryFromIntError {}
23
24#[stable(feature = "try_from", since = "1.34.0")]
25#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
26impl const From<Infallible> for TryFromIntError {
27    fn from(x: Infallible) -> TryFromIntError {
28        match x {}
29    }
30}
31
32#[unstable(feature = "never_type", issue = "35121")]
33#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
34impl const From<!> for TryFromIntError {
35    #[inline]
36    fn from(never: !) -> TryFromIntError {
37        // Match rather than coerce to make sure that code like
38        // `From<Infallible> for TryFromIntError` above will keep working
39        // when `Infallible` becomes an alias to `!`.
40        match never {}
41    }
42}
43
44/// An error which can be returned when parsing an integer.
45///
46/// For example, this error is returned by the `from_str_radix()` functions
47/// on the primitive integer types (such as [`i8::from_str_radix`])
48/// and is used as the error type in their [`FromStr`] implementations.
49///
50/// [`FromStr`]: crate::str::FromStr
51///
52/// # Potential causes
53///
54/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
55/// in the string e.g., when it is obtained from the standard input.
56/// Using the [`str::trim()`] method ensures that no whitespace remains before parsing.
57///
58/// # Example
59///
60/// ```
61/// if let Err(e) = i32::from_str_radix("a12", 10) {
62///     println!("Failed conversion to i32: {e}");
63/// }
64/// ```
65#[derive(Debug, Clone, PartialEq, Eq)]
66#[stable(feature = "rust1", since = "1.0.0")]
67pub struct ParseIntError {
68    pub(super) kind: IntErrorKind,
69}
70
71/// Enum to store the various types of errors that can cause parsing an integer to fail.
72///
73/// # Example
74///
75/// ```
76/// # fn main() {
77/// if let Err(e) = i32::from_str_radix("a12", 10) {
78///     println!("Failed conversion to i32: {:?}", e.kind());
79/// }
80/// # }
81/// ```
82#[stable(feature = "int_error_matching", since = "1.55.0")]
83#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash)]
84#[non_exhaustive]
85pub enum IntErrorKind {
86    /// Value being parsed is empty.
87    ///
88    /// This variant will be constructed when parsing an empty string.
89    #[stable(feature = "int_error_matching", since = "1.55.0")]
90    Empty,
91    /// Contains an invalid digit in its context.
92    ///
93    /// Among other causes, this variant will be constructed when parsing a string that
94    /// contains a non-ASCII char.
95    ///
96    /// This variant is also constructed when a `+` or `-` is misplaced within a string
97    /// either on its own or in the middle of a number.
98    #[stable(feature = "int_error_matching", since = "1.55.0")]
99    InvalidDigit,
100    /// Integer is too large to store in target integer type.
101    #[stable(feature = "int_error_matching", since = "1.55.0")]
102    PosOverflow,
103    /// Integer is too small to store in target integer type.
104    #[stable(feature = "int_error_matching", since = "1.55.0")]
105    NegOverflow,
106    /// Value was Zero
107    ///
108    /// This variant will be emitted when the parsing string has a value of zero, which
109    /// would be illegal for non-zero types.
110    #[stable(feature = "int_error_matching", since = "1.55.0")]
111    Zero,
112}
113
114impl ParseIntError {
115    /// Outputs the detailed cause of parsing an integer failing.
116    #[must_use]
117    #[rustc_const_stable(feature = "const_int_from_str", since = "1.82.0")]
118    #[stable(feature = "int_error_matching", since = "1.55.0")]
119    pub const fn kind(&self) -> &IntErrorKind {
120        &self.kind
121    }
122}
123
124#[stable(feature = "rust1", since = "1.0.0")]
125impl fmt::Display for ParseIntError {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        match self.kind {
128            IntErrorKind::Empty => "cannot parse integer from empty string",
129            IntErrorKind::InvalidDigit => "invalid digit found in string",
130            IntErrorKind::PosOverflow => "number too large to fit in target type",
131            IntErrorKind::NegOverflow => "number too small to fit in target type",
132            IntErrorKind::Zero => "number would be zero for non-zero type",
133        }
134        .fmt(f)
135    }
136}
137
138#[stable(feature = "rust1", since = "1.0.0")]
139#[cfg(not(feature = "ferrocene_subset"))]
140impl Error for ParseIntError {}