@@ -1939,14 +1939,16 @@ mod simd {
1939
1939
simd_arch_mod ! ( arm, int8x4_t, uint8x4_t) ;
1940
1940
}
1941
1941
1942
- // Used in `transmute!` below.
1942
+ // Used in macros below.
1943
1943
#[ doc( hidden) ]
1944
1944
pub use core:: mem:: transmute as __real_transmute;
1945
+ #[ doc( hidden) ]
1946
+ pub use core:: mem:: ManuallyDrop as __RealManuallyDrop;
1945
1947
1946
1948
/// Safely transmutes a value of one type to a value of another type of the same
1947
1949
/// size.
1948
1950
///
1949
- /// The expression `$e` must have a concrete type, `T`, which implements
1951
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
1950
1952
/// `AsBytes`. The `transmute!` expression must also have a concrete type, `U`
1951
1953
/// (`U` is inferred from the calling context), and `U` must implement
1952
1954
/// `FromBytes`.
@@ -1989,6 +1991,168 @@ macro_rules! transmute {
1989
1991
} }
1990
1992
}
1991
1993
1994
+ /// Safely attempts to transmute a value of one type to a value of another type
1995
+ /// of the same size, failing if the transmute would be unsound.
1996
+ ///
1997
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
1998
+ /// `AsBytes`. The `try_transmute!` expression must also have a concrete type,
1999
+ /// `Option<U>` (`U` is inferred from the calling context), and `U` must
2000
+ /// implement `TryFromBytes`.
2001
+ ///
2002
+ /// [`TryFromBytes::try_read_from`] is used to attempt to convert `$e` to the
2003
+ /// output type `U`. This will fail if the bytes of `$e` do not correspond to a
2004
+ /// valid instance of `U`.
2005
+ ///
2006
+ /// Note that the `T` produced by the expression `$e` will *not* be dropped.
2007
+ /// Semantically, its bits will be copied into a new value of type `U`, the
2008
+ /// original `T` will be forgotten, and the value of type `U` will be returned.
2009
+ ///
2010
+ /// # Examples
2011
+ ///
2012
+ /// ```rust
2013
+ /// # use zerocopy::try_transmute;
2014
+ /// assert_eq!(try_transmute!(1u8), Some(true));
2015
+ /// assert_eq!(try_transmute!(2u8), None::<bool>);
2016
+ ///
2017
+ /// assert_eq!(try_transmute!(108u32), Some('l'));
2018
+ /// assert_eq!(try_transmute!(0xD800u32), None::<char>);
2019
+ /// ```
2020
+ #[ macro_export]
2021
+ macro_rules! try_transmute {
2022
+ ( $e: expr) => { {
2023
+ // NOTE: This must be a macro (rather than a function with trait bounds)
2024
+ // because there's no way, in a generic context, to enforce that two
2025
+ // types have the same size. `core::mem::transmute` uses compiler magic
2026
+ // to enforce this so long as the types are concrete.
2027
+
2028
+ let e = $e;
2029
+ if false {
2030
+ // This branch, though never taken, ensures that the type of `e` is
2031
+ // `AsBytes` and that the type of this macro invocation expression
2032
+ // is `TryFromBytes`.
2033
+ const fn transmute<T : $crate:: AsBytes , U : $crate:: TryFromBytes >( _t: T ) -> U {
2034
+ unreachable!( )
2035
+ }
2036
+ Some ( transmute( e) )
2037
+ } else if false {
2038
+ // Though never executed, this ensures that the source and
2039
+ // destination types have the same size. This isn't strictly
2040
+ // necessary for soundness, but it turns what would otherwise be
2041
+ // runtime errors into compile-time errors.
2042
+ //
2043
+ // SAFETY: This branch never executes.
2044
+ Some ( unsafe { $crate:: __real_transmute( e) } )
2045
+ } else {
2046
+ // TODO: What's the correct drop behavior on `None`? Does this just
2047
+ // behave like `mem::forget` in that case?
2048
+ let m = $crate:: __RealManuallyDrop:: new( e) ;
2049
+ $crate:: TryFromBytes :: try_read_from( $crate:: AsBytes :: as_bytes( & m) )
2050
+ }
2051
+ } }
2052
+ }
2053
+
2054
+ /// Safely attempts to transmute a reference of one type to a reference of
2055
+ /// another type, failing if the transmute would be unsound.
2056
+ ///
2057
+ /// The expression, `$e`, must have a concrete type, `&T`, where `T: AsBytes`.
2058
+ /// The `try_transmute_ref!` expression must also have a concrete type,
2059
+ /// `Option<&U>` (`U` is inferred from the calling context), and `U` must
2060
+ /// implement `TryFromBytes`.
2061
+ ///
2062
+ /// [`TryFromBytes::try_from_ref`] is used to attempt to convert `$e` to the
2063
+ /// output reference type `&U`. This will fail if `$e` is not the right size, is
2064
+ /// not properly aligned, or if the bytes of `$e` do not correspond to a valid
2065
+ /// instance of `U`.
2066
+ ///
2067
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2068
+ /// which correspond to valid values of `U`.
2069
+ ///
2070
+ /// # Examples
2071
+ ///
2072
+ /// ```rust
2073
+ /// # use zerocopy::try_transmute_ref;
2074
+ /// # use zerocopy::AsBytes as _;
2075
+ /// let s: Option<&str> = try_transmute_ref!(&[104u8, 101, 108, 108, 111]);
2076
+ /// assert_eq!(s, Some("hello"));
2077
+ ///
2078
+ /// // Invalid UTF-8
2079
+ /// assert_eq!(try_transmute_ref!(&0xFFFFFFFFu32), None::<&str>);
2080
+ ///
2081
+ /// // Not enough bytes for a `u8`
2082
+ /// assert_eq!(try_transmute_ref!(&()), None::<&u8>);
2083
+ ///
2084
+ /// // Valid `&[[u8; 2]]` slices could be 2 or 4 bytes long,
2085
+ /// // but not 3.
2086
+ /// assert_eq!(try_transmute_ref!(&[0u8, 1, 2]), None::<&[[u8; 2]]>);
2087
+ ///
2088
+ /// // Guaranteed to be invalidly-aligned so long as
2089
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2090
+ /// // (this is true on most targets, but it isn't guaranteed).
2091
+ /// assert_eq!(try_transmute_ref!(&0u32.as_bytes()[1..]), None::<&u16>);
2092
+ /// ```
2093
+ #[ macro_export]
2094
+ macro_rules! try_transmute_ref {
2095
+ ( $e: expr) => {
2096
+ $crate:: TryFromBytes :: try_from_ref( $crate:: AsBytes :: as_bytes( $e) )
2097
+ } ;
2098
+ }
2099
+
2100
+ /// Safely attempts to transmute a mutable reference of one type to a mutable
2101
+ /// reference of another type, failing if the transmute would be unsound.
2102
+ ///
2103
+ /// The expression, `$e`, must have a concrete type, `&mut T`, where `T:
2104
+ /// FromBytes + AsBytes`. The `try_transmute_ref!` expression must also have a
2105
+ /// concrete type, `Option<&mut U>` (`U` is inferred from the calling context),
2106
+ /// and `U` must implement `TryFromBytes`.
2107
+ ///
2108
+ /// [`TryFromBytes::try_from_mut`] is used to attempt to convert `$e` to the
2109
+ /// output reference type, `&mut U`. This will fail if `$e` is not the right
2110
+ /// size, is not properly aligned, or if the bytes of `$e` do not correspond to
2111
+ /// a valid instance of `U`.
2112
+ ///
2113
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2114
+ /// which correspond to valid values of `U`.
2115
+ ///
2116
+ /// # Examples
2117
+ ///
2118
+ /// ```rust
2119
+ /// # use zerocopy::try_transmute_mut;
2120
+ /// # use zerocopy::AsBytes as _;
2121
+ /// let bytes = &mut [104u8, 101, 108, 108, 111];
2122
+ /// let mut s = try_transmute_mut!(bytes);
2123
+ /// assert_eq!(s, Some(String::from("hello").as_mut_str()));
2124
+ ///
2125
+ /// // Mutations to the transmuted reference are reflected
2126
+ /// // in the original reference.
2127
+ /// s.as_mut().unwrap().make_ascii_uppercase();
2128
+ /// assert_eq!(bytes, &[72, 69, 76, 76, 79]);
2129
+ ///
2130
+ /// // Invalid UTF-8
2131
+ /// let mut u = 0xFFFFFFFFu32;
2132
+ /// assert_eq!(try_transmute_mut!(&mut u), None::<&mut str>);
2133
+ ///
2134
+ /// // Not enough bytes for a `u8`
2135
+ /// let mut tuple = ();
2136
+ /// assert_eq!(try_transmute_mut!(&mut tuple), None::<&mut u8>);
2137
+ ///
2138
+ /// // Valid `&mut [[u8; 2]]` slices could be 2 or 4 bytes
2139
+ /// // long, but not 3.
2140
+ /// let bytes = &mut [0u8, 1, 2];
2141
+ /// assert_eq!(try_transmute_mut!(bytes), None::<&mut [[u8; 2]]>);
2142
+ ///
2143
+ /// // Guaranteed to be invalidly-aligned so long as
2144
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2145
+ /// // (this is true on most targets, but it isn't guaranteed).
2146
+ /// let mut u = 0u32;
2147
+ /// assert_eq!(try_transmute_mut!(&mut u.as_bytes_mut()[1..]), None::<&mut u16>);
2148
+ /// ```
2149
+ #[ macro_export]
2150
+ macro_rules! try_transmute_mut {
2151
+ ( $e: expr) => {
2152
+ $crate:: TryFromBytes :: try_from_mut( $crate:: AsBytes :: as_bytes_mut( $e) )
2153
+ } ;
2154
+ }
2155
+
1992
2156
/// A typed reference derived from a byte slice.
1993
2157
///
1994
2158
/// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`.
@@ -3599,10 +3763,16 @@ mod tests {
3599
3763
// Test that memory is transmuted as expected.
3600
3764
let array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3601
3765
let array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3766
+
3602
3767
let x: [ [ u8 ; 2 ] ; 4 ] = transmute ! ( array_of_u8s) ;
3603
3768
assert_eq ! ( x, array_of_arrays) ;
3769
+ let x: Option < [ [ u8 ; 2 ] ; 4 ] > = try_transmute ! ( array_of_u8s) ;
3770
+ assert_eq ! ( x, Some ( array_of_arrays) ) ;
3771
+
3604
3772
let x: [ u8 ; 8 ] = transmute ! ( array_of_arrays) ;
3605
3773
assert_eq ! ( x, array_of_u8s) ;
3774
+ let x: Option < [ u8 ; 8 ] > = try_transmute ! ( array_of_arrays) ;
3775
+ assert_eq ! ( x, Some ( array_of_u8s) ) ;
3606
3776
3607
3777
// Test that the source expression's value is forgotten rather than
3608
3778
// dropped.
@@ -3615,12 +3785,37 @@ mod tests {
3615
3785
}
3616
3786
}
3617
3787
let _: ( ) = transmute ! ( PanicOnDrop ( ( ) ) ) ;
3788
+ let _: Option < ( ) > = try_transmute ! ( PanicOnDrop ( ( ) ) ) ;
3618
3789
3619
3790
// Test that `transmute!` is legal in a const context.
3620
3791
const ARRAY_OF_U8S : [ u8 ; 8 ] = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3621
3792
const ARRAY_OF_ARRAYS : [ [ u8 ; 2 ] ; 4 ] = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3622
3793
const X : [ [ u8 ; 2 ] ; 4 ] = transmute ! ( ARRAY_OF_U8S ) ;
3623
3794
assert_eq ! ( X , ARRAY_OF_ARRAYS ) ;
3795
+
3796
+ // Test fallible transmutations with `try_transmute!`.
3797
+ let mut b: Option < bool > = try_transmute ! ( 0u8 ) ;
3798
+ assert_eq ! ( b, Some ( false ) ) ;
3799
+ b = try_transmute ! ( 1u8 ) ;
3800
+ assert_eq ! ( b, Some ( true ) ) ;
3801
+ b = try_transmute ! ( 2u8 ) ;
3802
+ assert_eq ! ( b, None ) ;
3803
+ }
3804
+
3805
+ #[ test]
3806
+ fn test_try_transmute_ref_mut ( ) {
3807
+ // These macros are dead-simple thin wrappers which delegate to other
3808
+ // traits. We only have this test to ensure that the macros are uesd
3809
+ // somewhere so our tests will break if the paths to various items
3810
+ // break.
3811
+ let x: Option < & [ u8 ; 2 ] > = try_transmute_ref ! ( & 0xFFFFu16 ) ;
3812
+ assert_eq ! ( x, Some ( & [ 255 , 255 ] ) ) ;
3813
+
3814
+ let mut u = 0xFFFFu16 ;
3815
+ let x: Option < & mut [ u8 ; 2 ] > = try_transmute_mut ! ( & mut u) ;
3816
+ assert_eq ! ( x, Some ( & mut [ 255 , 255 ] ) ) ;
3817
+ * x. unwrap ( ) = [ 0 , 0 ] ;
3818
+ assert_eq ! ( u, 0 ) ;
3624
3819
}
3625
3820
3626
3821
#[ test]
0 commit comments