Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 73 additions & 48 deletions library/core/src/convert/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,63 +39,52 @@ impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i12
impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
impl_float_to_int!(f128 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

// Conversion traits for primitive integer and float types
// Conversions T -> T are covered by a blanket impl and therefore excluded
// Some conversions from and to usize/isize are not implemented due to portability concerns
/// Implement `From<bool>` for integers
macro_rules! impl_from_bool {
($($int:ty)*) => {$(
#[stable(feature = "from_bool", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl const From<bool> for $int {
/// Converts from [`bool`] to
#[doc = concat!("[`", stringify!($int), "`]")]
/// , by turning `false` into `0` and `true` into `1`.
///
/// # Examples
///
/// ```
#[doc = concat!("assert_eq!(", stringify!($int), "::from(false), 0);")]
///
#[doc = concat!("assert_eq!(", stringify!($int), "::from(true), 1);")]
/// ```
#[inline(always)]
fn from(b: bool) -> Self {
b as Self
}
}
)*}
}

// boolean -> integer
impl_from_bool!(u8 u16 u32 u64 u128 usize);
impl_from_bool!(i8 i16 i32 i64 i128 isize);

/// Implement `From<$small>` for `$large`
macro_rules! impl_from {
(bool => $Int:ty $(,)?) => {
impl_from!(
bool => $Int,
#[stable(feature = "from_bool", since = "1.28.0")],
concat!(
"Converts a [`bool`] to [`", stringify!($Int), "`] losslessly.\n",
"The resulting value is `0` for `false` and `1` for `true` values.\n",
"\n",
"# Examples\n",
"\n",
"```\n",
"assert_eq!(", stringify!($Int), "::from(true), 1);\n",
"assert_eq!(", stringify!($Int), "::from(false), 0);\n",
"```\n",
),
);
};
($Small:ty => $Large:ty, #[$attr:meta] $(,)?) => {
impl_from!(
$Small => $Large,
#[$attr],
concat!("Converts [`", stringify!($Small), "`] to [`", stringify!($Large), "`] losslessly."),
);
};
($Small:ty => $Large:ty, #[$attr:meta], $doc:expr $(,)?) => {
($small:ty => $large:ty, #[$attr:meta]) => {
#[$attr]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl const From<$Small> for $Large {
// Rustdocs on the impl block show a "[+] show undocumented items" toggle.
// Rustdocs on functions do not.
#[doc = $doc]
impl const From<$small> for $large {
#[doc = concat!("Converts from [`", stringify!($small), "`] to [`", stringify!($large), "`] losslessly.")]
#[inline(always)]
fn from(small: $Small) -> Self {
fn from(small: $small) -> Self {
debug_assert!(<$large>::MIN as i128 <= <$small>::MIN as i128);
debug_assert!(<$small>::MAX as u128 <= <$large>::MAX as u128);
small as Self
}
}
};
}
}

// boolean -> integer
impl_from!(bool => u8);
impl_from!(bool => u16);
impl_from!(bool => u32);
impl_from!(bool => u64);
impl_from!(bool => u128);
impl_from!(bool => usize);
impl_from!(bool => i8);
impl_from!(bool => i16);
impl_from!(bool => i32);
impl_from!(bool => i64);
impl_from!(bool => i128);
impl_from!(bool => isize);

// unsigned integer -> unsigned integer
impl_from!(u8 => u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
impl_from!(u8 => u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]);
Expand Down Expand Up @@ -338,12 +327,48 @@ macro_rules! impl_try_from_both_bounded {
)*}
}

/// Implement `TryFrom<integer>` for `bool`
macro_rules! impl_try_from_integer_for_bool {
($($int:ty)+) => {$(
#[stable(feature = "try_from", since = "1.34.0")]
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
impl const TryFrom<$int> for bool {
type Error = TryFromIntError;
Comment on lines +333 to +336
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This used a feature gate with the wrong version. Fix in #154691

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.


/// Tries to create a bool from an integer type.
/// Returns an error if the integer is not 0 or 1.
///
/// # Examples
///
/// ```
#[doc = concat!("assert_eq!(0_", stringify!($int), ".try_into(), Ok(false));")]
///
#[doc = concat!("assert_eq!(1_", stringify!($int), ".try_into(), Ok(true));")]
///
#[doc = concat!("assert!(<", stringify!($int), " as TryInto<bool>>::try_into(2).is_err());")]
/// ```
#[inline]
fn try_from(i: $int) -> Result<Self, Self::Error> {
match i {
0 => Ok(false),
1 => Ok(true),
_ => Err(TryFromIntError(())),
}
}
}
)*}
}

macro_rules! rev {
($mac:ident, $source:ty => $($target:ty),+) => {$(
$mac!($target => $source);
)*}
}

// integer -> bool
impl_try_from_integer_for_bool!(u128 u64 u32 u16 u8);
impl_try_from_integer_for_bool!(i128 i64 i32 i16 i8);
Comment on lines +369 to +370
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this not have included usize/isize?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question! I don't recall intentionally excluding those, and a cursory review brings up no reason for excluding them, so this seems to have been an oversight on my part. Feel free to open a new PR to add those.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would caution against trying to beta backport a stabilization of additional API surface


// unsigned integer -> unsigned integer
impl_try_from_upper_bounded!(u16 => u8);
impl_try_from_upper_bounded!(u32 => u8, u16);
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/try-trait/bad-interconversion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ help: the following other types implement trait `From<T>`
::: $SRC_DIR/core/src/ascii/ascii_char.rs:LL:COL
|
= note: in this macro invocation
= note: this error originates in the macro `impl_from` which comes from the expansion of the macro `into_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
= note: this error originates in the macro `impl_from_bool` which comes from the expansion of the macro `into_int_impl` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> $DIR/bad-interconversion.rs:9:12
Expand Down
Loading