@@ -1954,14 +1954,16 @@ mod simd {
1954
1954
simd_arch_mod ! ( arm, int8x4_t, uint8x4_t) ;
1955
1955
}
1956
1956
1957
- // Used in `transmute!` below.
1957
+ // Used in macros below.
1958
1958
#[ doc( hidden) ]
1959
1959
pub use core:: mem:: transmute as __real_transmute;
1960
+ #[ doc( hidden) ]
1961
+ pub use core:: mem:: ManuallyDrop as __RealManuallyDrop;
1960
1962
1961
1963
/// Safely transmutes a value of one type to a value of another type of the same
1962
1964
/// size.
1963
1965
///
1964
- /// The expression `$e` must have a concrete type, `T`, which implements
1966
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
1965
1967
/// `AsBytes`. The `transmute!` expression must also have a concrete type, `U`
1966
1968
/// (`U` is inferred from the calling context), and `U` must implement
1967
1969
/// `FromBytes`.
@@ -2004,6 +2006,168 @@ macro_rules! transmute {
2004
2006
} }
2005
2007
}
2006
2008
2009
+ /// Safely attempts to transmute a value of one type to a value of another type
2010
+ /// of the same size, failing if the transmute would be unsound.
2011
+ ///
2012
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
2013
+ /// `AsBytes`. The `try_transmute!` expression must also have a concrete type,
2014
+ /// `Option<U>` (`U` is inferred from the calling context), and `U` must
2015
+ /// implement `TryFromBytes`.
2016
+ ///
2017
+ /// [`TryFromBytes::try_read_from`] is used to attempt to convert `$e` to the
2018
+ /// output type `U`. This will fail if the bytes of `$e` do not correspond to a
2019
+ /// valid instance of `U`.
2020
+ ///
2021
+ /// Note that the `T` produced by the expression `$e` will *not* be dropped.
2022
+ /// Semantically, its bits will be copied into a new value of type `U`, the
2023
+ /// original `T` will be forgotten, and the value of type `U` will be returned.
2024
+ ///
2025
+ /// # Examples
2026
+ ///
2027
+ /// ```rust
2028
+ /// # use zerocopy::try_transmute;
2029
+ /// assert_eq!(try_transmute!(1u8), Some(true));
2030
+ /// assert_eq!(try_transmute!(2u8), None::<bool>);
2031
+ ///
2032
+ /// assert_eq!(try_transmute!(108u32), Some('l'));
2033
+ /// assert_eq!(try_transmute!(0xD800u32), None::<char>);
2034
+ /// ```
2035
+ #[ macro_export]
2036
+ macro_rules! try_transmute {
2037
+ ( $e: expr) => { {
2038
+ // NOTE: This must be a macro (rather than a function with trait bounds)
2039
+ // because there's no way, in a generic context, to enforce that two
2040
+ // types have the same size. `core::mem::transmute` uses compiler magic
2041
+ // to enforce this so long as the types are concrete.
2042
+
2043
+ let e = $e;
2044
+ if false {
2045
+ // This branch, though never taken, ensures that the type of `e` is
2046
+ // `AsBytes` and that the type of this macro invocation expression
2047
+ // is `TryFromBytes`.
2048
+ const fn transmute<T : $crate:: AsBytes , U : $crate:: TryFromBytes >( _t: T ) -> U {
2049
+ unreachable!( )
2050
+ }
2051
+ Some ( transmute( e) )
2052
+ } else if false {
2053
+ // Though never executed, this ensures that the source and
2054
+ // destination types have the same size. This isn't strictly
2055
+ // necessary for soundness, but it turns what would otherwise be
2056
+ // runtime errors into compile-time errors.
2057
+ //
2058
+ // SAFETY: This branch never executes.
2059
+ Some ( unsafe { $crate:: __real_transmute( e) } )
2060
+ } else {
2061
+ // TODO: What's the correct drop behavior on `None`? Does this just
2062
+ // behave like `mem::forget` in that case?
2063
+ let m = $crate:: __RealManuallyDrop:: new( e) ;
2064
+ $crate:: TryFromBytes :: try_read_from( $crate:: AsBytes :: as_bytes( & m) )
2065
+ }
2066
+ } }
2067
+ }
2068
+
2069
+ /// Safely attempts to transmute a reference of one type to a reference of
2070
+ /// another type, failing if the transmute would be unsound.
2071
+ ///
2072
+ /// The expression, `$e`, must have a concrete type, `&T`, where `T: AsBytes`.
2073
+ /// The `try_transmute_ref!` expression must also have a concrete type,
2074
+ /// `Option<&U>` (`U` is inferred from the calling context), and `U` must
2075
+ /// implement `TryFromBytes`.
2076
+ ///
2077
+ /// [`TryFromBytes::try_from_ref`] is used to attempt to convert `$e` to the
2078
+ /// output reference type `&U`. This will fail if `$e` is not the right size, is
2079
+ /// not properly aligned, or if the bytes of `$e` do not correspond to a valid
2080
+ /// instance of `U`.
2081
+ ///
2082
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2083
+ /// which correspond to valid values of `U`.
2084
+ ///
2085
+ /// # Examples
2086
+ ///
2087
+ /// ```rust
2088
+ /// # use zerocopy::try_transmute_ref;
2089
+ /// # use zerocopy::AsBytes as _;
2090
+ /// let s: Option<&str> = try_transmute_ref!(&[104u8, 101, 108, 108, 111]);
2091
+ /// assert_eq!(s, Some("hello"));
2092
+ ///
2093
+ /// // Invalid UTF-8
2094
+ /// assert_eq!(try_transmute_ref!(&0xFFFFFFFFu32), None::<&str>);
2095
+ ///
2096
+ /// // Not enough bytes for a `u8`
2097
+ /// assert_eq!(try_transmute_ref!(&()), None::<&u8>);
2098
+ ///
2099
+ /// // Valid `&[[u8; 2]]` slices could be 2 or 4 bytes long,
2100
+ /// // but not 3.
2101
+ /// assert_eq!(try_transmute_ref!(&[0u8, 1, 2]), None::<&[[u8; 2]]>);
2102
+ ///
2103
+ /// // Guaranteed to be invalidly-aligned so long as
2104
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2105
+ /// // (this is true on most targets, but it isn't guaranteed).
2106
+ /// assert_eq!(try_transmute_ref!(&0u32.as_bytes()[1..]), None::<&u16>);
2107
+ /// ```
2108
+ #[ macro_export]
2109
+ macro_rules! try_transmute_ref {
2110
+ ( $e: expr) => {
2111
+ $crate:: TryFromBytes :: try_from_ref( $crate:: AsBytes :: as_bytes( $e) )
2112
+ } ;
2113
+ }
2114
+
2115
+ /// Safely attempts to transmute a mutable reference of one type to a mutable
2116
+ /// reference of another type, failing if the transmute would be unsound.
2117
+ ///
2118
+ /// The expression, `$e`, must have a concrete type, `&mut T`, where `T:
2119
+ /// FromBytes + AsBytes`. The `try_transmute_ref!` expression must also have a
2120
+ /// concrete type, `Option<&mut U>` (`U` is inferred from the calling context),
2121
+ /// and `U` must implement `TryFromBytes`.
2122
+ ///
2123
+ /// [`TryFromBytes::try_from_mut`] is used to attempt to convert `$e` to the
2124
+ /// output reference type, `&mut U`. This will fail if `$e` is not the right
2125
+ /// size, is not properly aligned, or if the bytes of `$e` do not correspond to
2126
+ /// a valid instance of `U`.
2127
+ ///
2128
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2129
+ /// which correspond to valid values of `U`.
2130
+ ///
2131
+ /// # Examples
2132
+ ///
2133
+ /// ```rust
2134
+ /// # use zerocopy::try_transmute_mut;
2135
+ /// # use zerocopy::AsBytes as _;
2136
+ /// let bytes = &mut [104u8, 101, 108, 108, 111];
2137
+ /// let mut s = try_transmute_mut!(bytes);
2138
+ /// assert_eq!(s, Some(String::from("hello").as_mut_str()));
2139
+ ///
2140
+ /// // Mutations to the transmuted reference are reflected
2141
+ /// // in the original reference.
2142
+ /// s.as_mut().unwrap().make_ascii_uppercase();
2143
+ /// assert_eq!(bytes, &[72, 69, 76, 76, 79]);
2144
+ ///
2145
+ /// // Invalid UTF-8
2146
+ /// let mut u = 0xFFFFFFFFu32;
2147
+ /// assert_eq!(try_transmute_mut!(&mut u), None::<&mut str>);
2148
+ ///
2149
+ /// // Not enough bytes for a `u8`
2150
+ /// let mut tuple = ();
2151
+ /// assert_eq!(try_transmute_mut!(&mut tuple), None::<&mut u8>);
2152
+ ///
2153
+ /// // Valid `&mut [[u8; 2]]` slices could be 2 or 4 bytes
2154
+ /// // long, but not 3.
2155
+ /// let bytes = &mut [0u8, 1, 2];
2156
+ /// assert_eq!(try_transmute_mut!(bytes), None::<&mut [[u8; 2]]>);
2157
+ ///
2158
+ /// // Guaranteed to be invalidly-aligned so long as
2159
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2160
+ /// // (this is true on most targets, but it isn't guaranteed).
2161
+ /// let mut u = 0u32;
2162
+ /// assert_eq!(try_transmute_mut!(&mut u.as_bytes_mut()[1..]), None::<&mut u16>);
2163
+ /// ```
2164
+ #[ macro_export]
2165
+ macro_rules! try_transmute_mut {
2166
+ ( $e: expr) => {
2167
+ $crate:: TryFromBytes :: try_from_mut( $crate:: AsBytes :: as_bytes_mut( $e) )
2168
+ } ;
2169
+ }
2170
+
2007
2171
/// A typed reference derived from a byte slice.
2008
2172
///
2009
2173
/// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`.
@@ -3685,10 +3849,16 @@ mod tests {
3685
3849
// Test that memory is transmuted as expected.
3686
3850
let array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3687
3851
let array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3852
+
3688
3853
let x: [ [ u8 ; 2 ] ; 4 ] = transmute ! ( array_of_u8s) ;
3689
3854
assert_eq ! ( x, array_of_arrays) ;
3855
+ let x: Option < [ [ u8 ; 2 ] ; 4 ] > = try_transmute ! ( array_of_u8s) ;
3856
+ assert_eq ! ( x, Some ( array_of_arrays) ) ;
3857
+
3690
3858
let x: [ u8 ; 8 ] = transmute ! ( array_of_arrays) ;
3691
3859
assert_eq ! ( x, array_of_u8s) ;
3860
+ let x: Option < [ u8 ; 8 ] > = try_transmute ! ( array_of_arrays) ;
3861
+ assert_eq ! ( x, Some ( array_of_u8s) ) ;
3692
3862
3693
3863
// Test that the source expression's value is forgotten rather than
3694
3864
// dropped.
@@ -3701,12 +3871,37 @@ mod tests {
3701
3871
}
3702
3872
}
3703
3873
let _: ( ) = transmute ! ( PanicOnDrop ( ( ) ) ) ;
3874
+ let _: Option < ( ) > = try_transmute ! ( PanicOnDrop ( ( ) ) ) ;
3704
3875
3705
3876
// Test that `transmute!` is legal in a const context.
3706
3877
const ARRAY_OF_U8S : [ u8 ; 8 ] = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3707
3878
const ARRAY_OF_ARRAYS : [ [ u8 ; 2 ] ; 4 ] = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3708
3879
const X : [ [ u8 ; 2 ] ; 4 ] = transmute ! ( ARRAY_OF_U8S ) ;
3709
3880
assert_eq ! ( X , ARRAY_OF_ARRAYS ) ;
3881
+
3882
+ // Test fallible transmutations with `try_transmute!`.
3883
+ let mut b: Option < bool > = try_transmute ! ( 0u8 ) ;
3884
+ assert_eq ! ( b, Some ( false ) ) ;
3885
+ b = try_transmute ! ( 1u8 ) ;
3886
+ assert_eq ! ( b, Some ( true ) ) ;
3887
+ b = try_transmute ! ( 2u8 ) ;
3888
+ assert_eq ! ( b, None ) ;
3889
+ }
3890
+
3891
+ #[ test]
3892
+ fn test_try_transmute_ref_mut ( ) {
3893
+ // These macros are dead-simple thin wrappers which delegate to other
3894
+ // traits. We only have this test to ensure that the macros are uesd
3895
+ // somewhere so our tests will break if the paths to various items
3896
+ // break.
3897
+ let x: Option < & [ u8 ; 2 ] > = try_transmute_ref ! ( & 0xFFFFu16 ) ;
3898
+ assert_eq ! ( x, Some ( & [ 255 , 255 ] ) ) ;
3899
+
3900
+ let mut u = 0xFFFFu16 ;
3901
+ let x: Option < & mut [ u8 ; 2 ] > = try_transmute_mut ! ( & mut u) ;
3902
+ assert_eq ! ( x, Some ( & mut [ 255 , 255 ] ) ) ;
3903
+ * x. unwrap ( ) = [ 0 , 0 ] ;
3904
+ assert_eq ! ( u, 0 ) ;
3710
3905
}
3711
3906
3712
3907
#[ test]
0 commit comments