@@ -1987,21 +1987,43 @@ mod simd {
1987
1987
simd_arch_mod ! ( arm, int8x4_t, uint8x4_t) ;
1988
1988
}
1989
1989
1990
- // Used in `transmute!` below.
1990
+ // Used in macros below.
1991
1991
#[ doc( hidden) ]
1992
1992
pub use core:: mem:: transmute as __real_transmute;
1993
+ #[ doc( hidden) ]
1994
+ pub use core:: mem:: ManuallyDrop as __RealManuallyDrop;
1993
1995
1994
1996
/// Safely transmutes a value of one type to a value of another type of the same
1995
1997
/// size.
1996
1998
///
1997
- /// The expression `$e` must have a concrete type, `T`, which implements
1998
- /// `AsBytes`. The `transmute!` expression must also have a concrete type, `U`
1999
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
2000
+ /// [ `AsBytes`] . The `transmute!` expression must also have a concrete type, `U`
1999
2001
/// (`U` is inferred from the calling context), and `U` must implement
2000
- /// `FromBytes`.
2002
+ /// [ `FromBytes`]. `T` and `U` must have the same size .
2001
2003
///
2002
2004
/// Note that the `T` produced by the expression `$e` will *not* be dropped.
2003
2005
/// Semantically, its bits will be copied into a new value of type `U`, the
2004
2006
/// original `T` will be forgotten, and the value of type `U` will be returned.
2007
+ ///
2008
+ /// # Examples
2009
+ ///
2010
+ /// ```rust
2011
+ /// # use zerocopy::transmute;
2012
+ /// use core::num::NonZeroU64;
2013
+ ///
2014
+ /// // Why would you want to do this? Who knows ¯\_(ツ)_/¯
2015
+ /// let opt: Option<NonZeroU64> = transmute!(0.0f64);
2016
+ /// assert_eq!(opt, None);
2017
+ /// ```
2018
+ ///
2019
+ /// ```rust,compile_fail
2020
+ /// # use zerocopy::try_transmute;
2021
+ /// // Fails to compile: `bool` does not implement `FromBytes`
2022
+ /// assert_eq!(transmute!(1u8), true);
2023
+ ///
2024
+ /// // Fails to compile: can't transmute between sizes of different types
2025
+ /// let _: u8 = try_transmute!(0u16);
2026
+ /// ```
2005
2027
#[ macro_export]
2006
2028
macro_rules! transmute {
2007
2029
( $e: expr) => { {
@@ -2037,6 +2059,178 @@ macro_rules! transmute {
2037
2059
} }
2038
2060
}
2039
2061
2062
+ /// Safely attempts to transmute a value of one type to a value of another type
2063
+ /// of the same size, failing if the transmute would be unsound.
2064
+ ///
2065
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
2066
+ /// [`AsBytes`]. The `try_transmute!` expression must also have a concrete type,
2067
+ /// `Option<U>` (`U` is inferred from the calling context), and `U` must
2068
+ /// implement [`TryFromBytes`]. `T` and `U` must have the same size.
2069
+ ///
2070
+ /// [`TryFromBytes::try_read_from`] is used to attempt to convert `$e` to the
2071
+ /// output type `U`. This will fail if the bytes of `$e` do not correspond to a
2072
+ /// valid instance of `U`.
2073
+ ///
2074
+ /// Note that the `T` produced by the expression `$e` will *not* be dropped.
2075
+ /// Semantically, its bits will be copied into a new value of type `U`, the
2076
+ /// original `T` will be forgotten, and the value of type `U` will be returned.
2077
+ ///
2078
+ /// # Examples
2079
+ ///
2080
+ /// ```rust
2081
+ /// # use zerocopy::try_transmute;
2082
+ /// assert_eq!(try_transmute!(1u8), Some(true));
2083
+ /// assert_eq!(try_transmute!(2u8), None::<bool>);
2084
+ ///
2085
+ /// assert_eq!(try_transmute!(108u32), Some('l'));
2086
+ /// assert_eq!(try_transmute!(0xD800u32), None::<char>);
2087
+ /// ```
2088
+ ///
2089
+ /// ```rust,compile_fail
2090
+ /// # use zerocopy::try_transmute;
2091
+ /// // Attempting to transmute from 2 to 1 bytes will fail to compile
2092
+ /// let _: Option<u8> = try_transmute!(0u16);
2093
+ /// ```
2094
+ #[ macro_export]
2095
+ macro_rules! try_transmute {
2096
+ ( $e: expr) => { {
2097
+ // NOTE: This must be a macro (rather than a function with trait bounds)
2098
+ // because there's no way, in a generic context, to enforce that two
2099
+ // types have the same size. `core::mem::transmute` uses compiler magic
2100
+ // to enforce this so long as the types are concrete.
2101
+
2102
+ let e = $e;
2103
+ if false {
2104
+ // This branch, though never taken, ensures that the type of `e` is
2105
+ // `AsBytes` and that the type of this macro invocation expression
2106
+ // is `TryFromBytes`.
2107
+ const fn transmute<T : $crate:: AsBytes , U : $crate:: TryFromBytes >( _t: T ) -> U {
2108
+ unreachable!( )
2109
+ }
2110
+ Some ( transmute( e) )
2111
+ } else if false {
2112
+ // Though never executed, this ensures that the source and
2113
+ // destination types have the same size. This isn't strictly
2114
+ // necessary for soundness, but it turns what would otherwise be
2115
+ // runtime errors into compile-time errors.
2116
+ //
2117
+ // SAFETY: This branch never executes.
2118
+ Some ( unsafe { $crate:: __real_transmute( e) } )
2119
+ } else {
2120
+ // TODO: What's the correct drop behavior on `None`? Does this just
2121
+ // behave like `mem::forget` in that case?
2122
+ let m = $crate:: __RealManuallyDrop:: new( e) ;
2123
+ $crate:: TryFromBytes :: try_read_from( $crate:: AsBytes :: as_bytes( & m) )
2124
+ }
2125
+ } }
2126
+ }
2127
+
2128
+ /// Safely attempts to transmute a reference of one type to a reference of
2129
+ /// another type, failing if the transmute would be unsound.
2130
+ ///
2131
+ /// The expression, `$e`, must have a concrete type, `&T`, where [`T: AsBytes`].
2132
+ /// The `try_transmute_ref!` expression must also have a concrete type,
2133
+ /// `Option<&U>` (`U` is inferred from the calling context), and `U` must
2134
+ /// implement [`TryFromBytes`].
2135
+ ///
2136
+ /// [`TryFromBytes::try_from_ref`] is used to attempt to convert `$e` to the
2137
+ /// output reference type `&U`. This will fail if `$e` is not the right size, is
2138
+ /// not properly aligned, or if the bytes of `$e` do not correspond to a valid
2139
+ /// instance of `U`.
2140
+ ///
2141
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2142
+ /// which correspond to valid values of `U`.
2143
+ ///
2144
+ /// [`T: AsBytes`]: AsBytes
2145
+ ///
2146
+ /// # Examples
2147
+ ///
2148
+ /// ```rust
2149
+ /// # use zerocopy::try_transmute_ref;
2150
+ /// # use zerocopy::AsBytes as _;
2151
+ /// let s: Option<&str> = try_transmute_ref!(&[104u8, 101, 108, 108, 111]);
2152
+ /// assert_eq!(s, Some("hello"));
2153
+ ///
2154
+ /// // Invalid UTF-8
2155
+ /// assert_eq!(try_transmute_ref!(&0xFFFFFFFFu32), None::<&str>);
2156
+ ///
2157
+ /// // Not enough bytes for a `u8`
2158
+ /// assert_eq!(try_transmute_ref!(&()), None::<&u8>);
2159
+ ///
2160
+ /// // Valid `&[[u8; 2]]` slices could be 2 or 4 bytes long,
2161
+ /// // but not 3.
2162
+ /// assert_eq!(try_transmute_ref!(&[0u8, 1, 2]), None::<&[[u8; 2]]>);
2163
+ ///
2164
+ /// // Guaranteed to be invalidly-aligned so long as
2165
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2166
+ /// // (this is true on most targets, but it isn't guaranteed).
2167
+ /// assert_eq!(try_transmute_ref!(&0u32.as_bytes()[1..]), None::<&u16>);
2168
+ /// ```
2169
+ #[ macro_export]
2170
+ macro_rules! try_transmute_ref {
2171
+ ( $e: expr) => {
2172
+ $crate:: TryFromBytes :: try_from_ref( $crate:: AsBytes :: as_bytes( $e) )
2173
+ } ;
2174
+ }
2175
+
2176
+ /// Safely attempts to transmute a mutable reference of one type to a mutable
2177
+ /// reference of another type, failing if the transmute would be unsound.
2178
+ ///
2179
+ /// The expression, `$e`, must have a concrete type, `&mut T`, where `T:
2180
+ /// FromBytes + AsBytes`. The `try_transmute_ref!` expression must also have a
2181
+ /// concrete type, `Option<&mut U>` (`U` is inferred from the calling context),
2182
+ /// and `U` must implement [`TryFromBytes`].
2183
+ ///
2184
+ /// [`TryFromBytes::try_from_mut`] is used to attempt to convert `$e` to the
2185
+ /// output reference type, `&mut U`. This will fail if `$e` is not the right
2186
+ /// size, is not properly aligned, or if the bytes of `$e` do not correspond to
2187
+ /// a valid instance of `U`.
2188
+ ///
2189
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2190
+ /// which correspond to valid values of `U`.
2191
+ ///
2192
+ /// [`TryFromBytes`]: TryFromBytes
2193
+ ///
2194
+ /// # Examples
2195
+ ///
2196
+ /// ```rust
2197
+ /// # use zerocopy::try_transmute_mut;
2198
+ /// # use zerocopy::AsBytes as _;
2199
+ /// let bytes = &mut [104u8, 101, 108, 108, 111];
2200
+ /// let mut s = try_transmute_mut!(bytes);
2201
+ /// assert_eq!(s, Some(String::from("hello").as_mut_str()));
2202
+ ///
2203
+ /// // Mutations to the transmuted reference are reflected
2204
+ /// // in the original reference.
2205
+ /// s.as_mut().unwrap().make_ascii_uppercase();
2206
+ /// assert_eq!(bytes, &[72, 69, 76, 76, 79]);
2207
+ ///
2208
+ /// // Invalid UTF-8
2209
+ /// let mut u = 0xFFFFFFFFu32;
2210
+ /// assert_eq!(try_transmute_mut!(&mut u), None::<&mut str>);
2211
+ ///
2212
+ /// // Not enough bytes for a `u8`
2213
+ /// let mut tuple = ();
2214
+ /// assert_eq!(try_transmute_mut!(&mut tuple), None::<&mut u8>);
2215
+ ///
2216
+ /// // Valid `&mut [[u8; 2]]` slices could be 2 or 4 bytes
2217
+ /// // long, but not 3.
2218
+ /// let bytes = &mut [0u8, 1, 2];
2219
+ /// assert_eq!(try_transmute_mut!(bytes), None::<&mut [[u8; 2]]>);
2220
+ ///
2221
+ /// // Guaranteed to be invalidly-aligned so long as
2222
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2223
+ /// // (this is true on most targets, but it isn't guaranteed).
2224
+ /// let mut u = 0u32;
2225
+ /// assert_eq!(try_transmute_mut!(&mut u.as_bytes_mut()[1..]), None::<&mut u16>);
2226
+ /// ```
2227
+ #[ macro_export]
2228
+ macro_rules! try_transmute_mut {
2229
+ ( $e: expr) => {
2230
+ $crate:: TryFromBytes :: try_from_mut( $crate:: AsBytes :: as_bytes_mut( $e) )
2231
+ } ;
2232
+ }
2233
+
2040
2234
/// A typed reference derived from a byte slice.
2041
2235
///
2042
2236
/// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`.
@@ -3718,10 +3912,16 @@ mod tests {
3718
3912
// Test that memory is transmuted as expected.
3719
3913
let array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3720
3914
let array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3915
+
3721
3916
let x: [ [ u8 ; 2 ] ; 4 ] = transmute ! ( array_of_u8s) ;
3722
3917
assert_eq ! ( x, array_of_arrays) ;
3918
+ let x: Option < [ [ u8 ; 2 ] ; 4 ] > = try_transmute ! ( array_of_u8s) ;
3919
+ assert_eq ! ( x, Some ( array_of_arrays) ) ;
3920
+
3723
3921
let x: [ u8 ; 8 ] = transmute ! ( array_of_arrays) ;
3724
3922
assert_eq ! ( x, array_of_u8s) ;
3923
+ let x: Option < [ u8 ; 8 ] > = try_transmute ! ( array_of_arrays) ;
3924
+ assert_eq ! ( x, Some ( array_of_u8s) ) ;
3725
3925
3726
3926
// Test that the source expression's value is forgotten rather than
3727
3927
// dropped.
@@ -3734,12 +3934,37 @@ mod tests {
3734
3934
}
3735
3935
}
3736
3936
let _: ( ) = transmute ! ( PanicOnDrop ( ( ) ) ) ;
3937
+ let _: Option < ( ) > = try_transmute ! ( PanicOnDrop ( ( ) ) ) ;
3737
3938
3738
3939
// Test that `transmute!` is legal in a const context.
3739
3940
const ARRAY_OF_U8S : [ u8 ; 8 ] = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3740
3941
const ARRAY_OF_ARRAYS : [ [ u8 ; 2 ] ; 4 ] = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3741
3942
const X : [ [ u8 ; 2 ] ; 4 ] = transmute ! ( ARRAY_OF_U8S ) ;
3742
3943
assert_eq ! ( X , ARRAY_OF_ARRAYS ) ;
3944
+
3945
+ // Test fallible transmutations with `try_transmute!`.
3946
+ let mut b: Option < bool > = try_transmute ! ( 0u8 ) ;
3947
+ assert_eq ! ( b, Some ( false ) ) ;
3948
+ b = try_transmute ! ( 1u8 ) ;
3949
+ assert_eq ! ( b, Some ( true ) ) ;
3950
+ b = try_transmute ! ( 2u8 ) ;
3951
+ assert_eq ! ( b, None ) ;
3952
+ }
3953
+
3954
+ #[ test]
3955
+ fn test_try_transmute_ref_mut ( ) {
3956
+ // These macros are dead-simple thin wrappers which delegate to other
3957
+ // traits. We only have this test to ensure that the macros are uesd
3958
+ // somewhere so our tests will break if the paths to various items
3959
+ // break.
3960
+ let x: Option < & [ u8 ; 2 ] > = try_transmute_ref ! ( & 0xFFFFu16 ) ;
3961
+ assert_eq ! ( x, Some ( & [ 255 , 255 ] ) ) ;
3962
+
3963
+ let mut u = 0xFFFFu16 ;
3964
+ let x: Option < & mut [ u8 ; 2 ] > = try_transmute_mut ! ( & mut u) ;
3965
+ assert_eq ! ( x, Some ( & mut [ 255 , 255 ] ) ) ;
3966
+ * x. unwrap ( ) = [ 0 , 0 ] ;
3967
+ assert_eq ! ( u, 0 ) ;
3743
3968
}
3744
3969
3745
3970
#[ test]
0 commit comments