Skip to main content

core/num/
error.rs

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