Skip to main content

core/num/
error.rs

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