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