@@ -1521,6 +1521,45 @@ pub unsafe trait TryFromBytes {
15211521 #[ doc( hidden) ]
15221522 fn is_bit_valid < A : invariant:: at_least:: Shared > ( candidate : Maybe < ' _ , Self , A > ) -> bool ;
15231523
1524+ /// Is a given source value a valid instance of `Self`?
1525+ ///
1526+ /// # Safety
1527+ ///
1528+ /// Unsafe code may assume that, if `is_bit_valid(src)` returns true, `*src`
1529+ /// is valid instance of `Self`.
1530+ ///
1531+ /// # Panics
1532+ ///
1533+ /// `is_src_valid` panics under exactly the same circumstances as
1534+ /// [`TryFromBytes::is_bit_valid`].
1535+ #[ doc( hidden) ]
1536+ #[ inline]
1537+ fn is_src_valid < Src > ( src : & mut Src ) -> bool
1538+ where
1539+ Src : IntoBytes ,
1540+ Self : Sized ,
1541+ {
1542+ let c_ptr = crate :: Ptr :: from_mut ( src) ;
1543+
1544+ if mem:: size_of :: < Src > ( ) > mem:: size_of :: < Self > ( ) {
1545+ return false ;
1546+ }
1547+
1548+ // SAFETY:
1549+ // - `size_of::<Src>()` <= `size_of::<Self>()`
1550+ // - `c_ptr` is exclusively aliased, so we do not need to reason about
1551+ // `UnsafeCell`
1552+ #[ allow( clippy:: as_conversions) ]
1553+ let c_ptr = unsafe { c_ptr. cast_unsized ( |p| p as * mut Self ) } ;
1554+
1555+ // SAFETY: `c_ptr` is derived from `src` which is `IntoBytes`. By
1556+ // invariant on `IntoByte`s, `c_ptr`'s referent consists entirely of
1557+ // initialized bytes.
1558+ let c_ptr = unsafe { c_ptr. assume_validity :: < crate :: invariant:: Initialized > ( ) } ;
1559+
1560+ Self :: is_bit_valid ( c_ptr)
1561+ }
1562+
15241563 /// Attempts to interpret a byte slice as a `Self`.
15251564 ///
15261565 /// `try_from_ref` validates that `bytes` contains a valid `Self`, and that
@@ -4732,6 +4771,63 @@ macro_rules! transmute_mut {
47324771 } }
47334772}
47344773
4774+ /// Conditionally transmutes a value of one type to a value of another type of
4775+ /// the same size.
4776+ ///
4777+ /// The expression `$e` must have a concrete type, `T`, which implements
4778+ /// [`IntoBytes`]. The `try_transmute!` expression must also have a concrete
4779+ /// type, `U` (`U` is inferred from the calling context), and `U` must implement
4780+ /// [`TryFromBytes`].
4781+ ///
4782+ /// Note that the `T` produced by the expression `$e` will *not* be dropped.
4783+ /// Semantically, its bits will be copied into a new value of type `U`, the
4784+ /// original `T` will be forgotten, and the value of type `U` will be returned.
4785+ ///
4786+ /// # Examples
4787+ ///
4788+ /// ```
4789+ /// # use zerocopy::try_transmute;
4790+ /// assert_eq!(try_transmute!(0u8), Some(false));
4791+ /// assert_eq!(try_transmute!(1u8), Some(true));
4792+ /// assert_eq!(try_transmute!(255u8), Option::<bool>::None);
4793+ /// ```
4794+ #[ macro_export]
4795+ macro_rules! try_transmute {
4796+ ( $e: expr) => { {
4797+ // NOTE: This must be a macro (rather than a function with trait bounds)
4798+ // because there's no way, in a generic context, to enforce that two
4799+ // types have the same size. `core::mem::transmute` uses compiler magic
4800+ // to enforce this so long as the types are concrete.
4801+
4802+ let e = $e;
4803+ if false {
4804+ // This branch, though never taken, ensures that the type of `e` is
4805+ // `IntoBytes` and that the type of this macro invocation expression
4806+ // is `TryFromBytes`.
4807+
4808+ struct AssertIsIntoBytes <T : $crate:: IntoBytes >( T ) ;
4809+ let _ = AssertIsIntoBytes ( e) ;
4810+
4811+ struct AssertIsTryFromBytes <U : $crate:: TryFromBytes >( U ) ;
4812+ #[ allow( unused, unreachable_code) ]
4813+ let u = AssertIsTryFromBytes ( loop { } ) ;
4814+ Some ( u. 0 )
4815+ } else if false {
4816+ // Check that the sizes of the source and destination types are
4817+ // equal.
4818+
4819+ // SAFETY: This code is never executed.
4820+ Some ( unsafe {
4821+ // Clippy: It's okay to transmute a type to itself.
4822+ #[ allow( clippy:: useless_transmute) ]
4823+ $crate:: macro_util:: core_reexport:: mem:: transmute( e)
4824+ } )
4825+ } else {
4826+ $crate:: macro_util:: try_transmute:: <_, _>( e)
4827+ }
4828+ } }
4829+ }
4830+
47354831/// Includes a file and safely transmutes it to a value of an arbitrary type.
47364832///
47374833/// The file will be included as a byte array, `[u8; N]`, which will be
0 commit comments