Repository: rust-lang/rust
Pull request: TryFrom<integer> for bool

I noticed the manual TryFrom implementation in [this video from RustConf 2025](https://youtu.be/cOP219vkax8?list=PL2b0df3jKKiRFEuVNk76ufXagOgEJ9sBZ&t=1917) and thought I'd add it.

Changed files:
filename: library/core/src/convert/num.rs
patch: @@ -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")]);
@@ -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;
+
+            /// 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);
+
 // unsigned integer -> unsigned integer
 impl_try_from_upper_bounded!(u16 => u8);
 impl_try_from_upper_bounded!(u32 => u8, u16);

filename: tests/ui/try-trait/bad-interconversion.stderr
patch: @@ -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