@@ -1960,21 +1960,43 @@ mod simd {
1960
1960
simd_arch_mod ! ( arm, int8x4_t, uint8x4_t) ;
1961
1961
}
1962
1962
1963
- // Used in `transmute!` below.
1963
+ // Used in macros below.
1964
1964
#[ doc( hidden) ]
1965
1965
pub use core:: mem:: transmute as __real_transmute;
1966
+ #[ doc( hidden) ]
1967
+ pub use core:: mem:: ManuallyDrop as __RealManuallyDrop;
1966
1968
1967
1969
/// Safely transmutes a value of one type to a value of another type of the same
1968
1970
/// size.
1969
1971
///
1970
- /// The expression `$e` must have a concrete type, `T`, which implements
1971
- /// `AsBytes`. The `transmute!` expression must also have a concrete type, `U`
1972
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
1973
+ /// [ `AsBytes`] . The `transmute!` expression must also have a concrete type, `U`
1972
1974
/// (`U` is inferred from the calling context), and `U` must implement
1973
- /// `FromBytes`.
1975
+ /// [ `FromBytes`]. `T` and `U` must have the same size .
1974
1976
///
1975
1977
/// Note that the `T` produced by the expression `$e` will *not* be dropped.
1976
1978
/// Semantically, its bits will be copied into a new value of type `U`, the
1977
1979
/// original `T` will be forgotten, and the value of type `U` will be returned.
1980
+ ///
1981
+ /// # Examples
1982
+ ///
1983
+ /// ```rust
1984
+ /// # use zerocopy::transmute;
1985
+ /// use core::num::NonZeroU64;
1986
+ ///
1987
+ /// // Why would you want to do this? Who knows ¯\_(ツ)_/¯
1988
+ /// let opt: Option<NonZeroU64> = transmute!(0.0f64);
1989
+ /// assert_eq!(opt, None);
1990
+ /// ```
1991
+ ///
1992
+ /// ```rust,compile_fail
1993
+ /// # use zerocopy::try_transmute;
1994
+ /// // Fails to compile: `bool` does not implement `FromBytes`
1995
+ /// assert_eq!(transmute!(1u8), true);
1996
+ ///
1997
+ /// // Fails to compile: can't transmute between sizes of different types
1998
+ /// let _: u8 = try_transmute!(0u16);
1999
+ /// ```
1978
2000
#[ macro_export]
1979
2001
macro_rules! transmute {
1980
2002
( $e: expr) => { {
@@ -2010,6 +2032,178 @@ macro_rules! transmute {
2010
2032
} }
2011
2033
}
2012
2034
2035
+ /// Safely attempts to transmute a value of one type to a value of another type
2036
+ /// of the same size, failing if the transmute would be unsound.
2037
+ ///
2038
+ /// The expression, `$e`, must have a concrete type, `T`, which implements
2039
+ /// [`AsBytes`]. The `try_transmute!` expression must also have a concrete type,
2040
+ /// `Option<U>` (`U` is inferred from the calling context), and `U` must
2041
+ /// implement [`TryFromBytes`]. `T` and `U` must have the same size.
2042
+ ///
2043
+ /// [`TryFromBytes::try_read_from`] is used to attempt to convert `$e` to the
2044
+ /// output type `U`. This will fail if the bytes of `$e` do not correspond to a
2045
+ /// valid instance of `U`.
2046
+ ///
2047
+ /// Note that the `T` produced by the expression `$e` will *not* be dropped.
2048
+ /// Semantically, its bits will be copied into a new value of type `U`, the
2049
+ /// original `T` will be forgotten, and the value of type `U` will be returned.
2050
+ ///
2051
+ /// # Examples
2052
+ ///
2053
+ /// ```rust
2054
+ /// # use zerocopy::try_transmute;
2055
+ /// assert_eq!(try_transmute!(1u8), Some(true));
2056
+ /// assert_eq!(try_transmute!(2u8), None::<bool>);
2057
+ ///
2058
+ /// assert_eq!(try_transmute!(108u32), Some('l'));
2059
+ /// assert_eq!(try_transmute!(0xD800u32), None::<char>);
2060
+ /// ```
2061
+ ///
2062
+ /// ```rust,compile_fail
2063
+ /// # use zerocopy::try_transmute;
2064
+ /// // Attempting to transmute from 2 to 1 bytes will fail to compile
2065
+ /// let _: Option<u8> = try_transmute!(0u16);
2066
+ /// ```
2067
+ #[ macro_export]
2068
+ macro_rules! try_transmute {
2069
+ ( $e: expr) => { {
2070
+ // NOTE: This must be a macro (rather than a function with trait bounds)
2071
+ // because there's no way, in a generic context, to enforce that two
2072
+ // types have the same size. `core::mem::transmute` uses compiler magic
2073
+ // to enforce this so long as the types are concrete.
2074
+
2075
+ let e = $e;
2076
+ if false {
2077
+ // This branch, though never taken, ensures that the type of `e` is
2078
+ // `AsBytes` and that the type of this macro invocation expression
2079
+ // is `TryFromBytes`.
2080
+ const fn transmute<T : $crate:: AsBytes , U : $crate:: TryFromBytes >( _t: T ) -> U {
2081
+ unreachable!( )
2082
+ }
2083
+ Some ( transmute( e) )
2084
+ } else if false {
2085
+ // Though never executed, this ensures that the source and
2086
+ // destination types have the same size. This isn't strictly
2087
+ // necessary for soundness, but it turns what would otherwise be
2088
+ // runtime errors into compile-time errors.
2089
+ //
2090
+ // SAFETY: This branch never executes.
2091
+ Some ( unsafe { $crate:: __real_transmute( e) } )
2092
+ } else {
2093
+ // TODO: What's the correct drop behavior on `None`? Does this just
2094
+ // behave like `mem::forget` in that case?
2095
+ let m = $crate:: __RealManuallyDrop:: new( e) ;
2096
+ $crate:: TryFromBytes :: try_read_from( $crate:: AsBytes :: as_bytes( & m) )
2097
+ }
2098
+ } }
2099
+ }
2100
+
2101
+ /// Safely attempts to transmute a reference of one type to a reference of
2102
+ /// another type, failing if the transmute would be unsound.
2103
+ ///
2104
+ /// The expression, `$e`, must have a concrete type, `&T`, where [`T: AsBytes`].
2105
+ /// The `try_transmute_ref!` expression must also have a concrete type,
2106
+ /// `Option<&U>` (`U` is inferred from the calling context), and `U` must
2107
+ /// implement [`TryFromBytes`].
2108
+ ///
2109
+ /// [`TryFromBytes::try_from_ref`] is used to attempt to convert `$e` to the
2110
+ /// output reference type `&U`. This will fail if `$e` is not the right size, is
2111
+ /// not properly aligned, or if the bytes of `$e` do not correspond to a valid
2112
+ /// instance of `U`.
2113
+ ///
2114
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2115
+ /// which correspond to valid values of `U`.
2116
+ ///
2117
+ /// [`T: AsBytes`]: AsBytes
2118
+ ///
2119
+ /// # Examples
2120
+ ///
2121
+ /// ```rust
2122
+ /// # use zerocopy::try_transmute_ref;
2123
+ /// # use zerocopy::AsBytes as _;
2124
+ /// let s: Option<&str> = try_transmute_ref!(&[104u8, 101, 108, 108, 111]);
2125
+ /// assert_eq!(s, Some("hello"));
2126
+ ///
2127
+ /// // Invalid UTF-8
2128
+ /// assert_eq!(try_transmute_ref!(&0xFFFFFFFFu32), None::<&str>);
2129
+ ///
2130
+ /// // Not enough bytes for a `u8`
2131
+ /// assert_eq!(try_transmute_ref!(&()), None::<&u8>);
2132
+ ///
2133
+ /// // Valid `&[[u8; 2]]` slices could be 2 or 4 bytes long,
2134
+ /// // but not 3.
2135
+ /// assert_eq!(try_transmute_ref!(&[0u8, 1, 2]), None::<&[[u8; 2]]>);
2136
+ ///
2137
+ /// // Guaranteed to be invalidly-aligned so long as
2138
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2139
+ /// // (this is true on most targets, but it isn't guaranteed).
2140
+ /// assert_eq!(try_transmute_ref!(&0u32.as_bytes()[1..]), None::<&u16>);
2141
+ /// ```
2142
+ #[ macro_export]
2143
+ macro_rules! try_transmute_ref {
2144
+ ( $e: expr) => {
2145
+ $crate:: TryFromBytes :: try_from_ref( $crate:: AsBytes :: as_bytes( $e) )
2146
+ } ;
2147
+ }
2148
+
2149
+ /// Safely attempts to transmute a mutable reference of one type to a mutable
2150
+ /// reference of another type, failing if the transmute would be unsound.
2151
+ ///
2152
+ /// The expression, `$e`, must have a concrete type, `&mut T`, where `T:
2153
+ /// FromBytes + AsBytes`. The `try_transmute_ref!` expression must also have a
2154
+ /// concrete type, `Option<&mut U>` (`U` is inferred from the calling context),
2155
+ /// and `U` must implement [`TryFromBytes`].
2156
+ ///
2157
+ /// [`TryFromBytes::try_from_mut`] is used to attempt to convert `$e` to the
2158
+ /// output reference type, `&mut U`. This will fail if `$e` is not the right
2159
+ /// size, is not properly aligned, or if the bytes of `$e` do not correspond to
2160
+ /// a valid instance of `U`.
2161
+ ///
2162
+ /// Note that, if `U` is an unsized type, there will be multiple sizes for `$e`
2163
+ /// which correspond to valid values of `U`.
2164
+ ///
2165
+ /// [`TryFromBytes`]: TryFromBytes
2166
+ ///
2167
+ /// # Examples
2168
+ ///
2169
+ /// ```rust
2170
+ /// # use zerocopy::try_transmute_mut;
2171
+ /// # use zerocopy::AsBytes as _;
2172
+ /// let bytes = &mut [104u8, 101, 108, 108, 111];
2173
+ /// let mut s = try_transmute_mut!(bytes);
2174
+ /// assert_eq!(s, Some(String::from("hello").as_mut_str()));
2175
+ ///
2176
+ /// // Mutations to the transmuted reference are reflected
2177
+ /// // in the original reference.
2178
+ /// s.as_mut().unwrap().make_ascii_uppercase();
2179
+ /// assert_eq!(bytes, &[72, 69, 76, 76, 79]);
2180
+ ///
2181
+ /// // Invalid UTF-8
2182
+ /// let mut u = 0xFFFFFFFFu32;
2183
+ /// assert_eq!(try_transmute_mut!(&mut u), None::<&mut str>);
2184
+ ///
2185
+ /// // Not enough bytes for a `u8`
2186
+ /// let mut tuple = ();
2187
+ /// assert_eq!(try_transmute_mut!(&mut tuple), None::<&mut u8>);
2188
+ ///
2189
+ /// // Valid `&mut [[u8; 2]]` slices could be 2 or 4 bytes
2190
+ /// // long, but not 3.
2191
+ /// let bytes = &mut [0u8, 1, 2];
2192
+ /// assert_eq!(try_transmute_mut!(bytes), None::<&mut [[u8; 2]]>);
2193
+ ///
2194
+ /// // Guaranteed to be invalidly-aligned so long as
2195
+ /// // `align_of::<u16>() == 2` and `align_of::<u32>() >= 2`
2196
+ /// // (this is true on most targets, but it isn't guaranteed).
2197
+ /// let mut u = 0u32;
2198
+ /// assert_eq!(try_transmute_mut!(&mut u.as_bytes_mut()[1..]), None::<&mut u16>);
2199
+ /// ```
2200
+ #[ macro_export]
2201
+ macro_rules! try_transmute_mut {
2202
+ ( $e: expr) => {
2203
+ $crate:: TryFromBytes :: try_from_mut( $crate:: AsBytes :: as_bytes_mut( $e) )
2204
+ } ;
2205
+ }
2206
+
2013
2207
/// A typed reference derived from a byte slice.
2014
2208
///
2015
2209
/// A `Ref<B, T>` is a reference to a `T` which is stored in a byte slice, `B`.
@@ -3691,10 +3885,16 @@ mod tests {
3691
3885
// Test that memory is transmuted as expected.
3692
3886
let array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3693
3887
let array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3888
+
3694
3889
let x: [ [ u8 ; 2 ] ; 4 ] = transmute ! ( array_of_u8s) ;
3695
3890
assert_eq ! ( x, array_of_arrays) ;
3891
+ let x: Option < [ [ u8 ; 2 ] ; 4 ] > = try_transmute ! ( array_of_u8s) ;
3892
+ assert_eq ! ( x, Some ( array_of_arrays) ) ;
3893
+
3696
3894
let x: [ u8 ; 8 ] = transmute ! ( array_of_arrays) ;
3697
3895
assert_eq ! ( x, array_of_u8s) ;
3896
+ let x: Option < [ u8 ; 8 ] > = try_transmute ! ( array_of_arrays) ;
3897
+ assert_eq ! ( x, Some ( array_of_u8s) ) ;
3698
3898
3699
3899
// Test that the source expression's value is forgotten rather than
3700
3900
// dropped.
@@ -3707,12 +3907,37 @@ mod tests {
3707
3907
}
3708
3908
}
3709
3909
let _: ( ) = transmute ! ( PanicOnDrop ( ( ) ) ) ;
3910
+ let _: Option < ( ) > = try_transmute ! ( PanicOnDrop ( ( ) ) ) ;
3710
3911
3711
3912
// Test that `transmute!` is legal in a const context.
3712
3913
const ARRAY_OF_U8S : [ u8 ; 8 ] = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3713
3914
const ARRAY_OF_ARRAYS : [ [ u8 ; 2 ] ; 4 ] = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3714
3915
const X : [ [ u8 ; 2 ] ; 4 ] = transmute ! ( ARRAY_OF_U8S ) ;
3715
3916
assert_eq ! ( X , ARRAY_OF_ARRAYS ) ;
3917
+
3918
+ // Test fallible transmutations with `try_transmute!`.
3919
+ let mut b: Option < bool > = try_transmute ! ( 0u8 ) ;
3920
+ assert_eq ! ( b, Some ( false ) ) ;
3921
+ b = try_transmute ! ( 1u8 ) ;
3922
+ assert_eq ! ( b, Some ( true ) ) ;
3923
+ b = try_transmute ! ( 2u8 ) ;
3924
+ assert_eq ! ( b, None ) ;
3925
+ }
3926
+
3927
+ #[ test]
3928
+ fn test_try_transmute_ref_mut ( ) {
3929
+ // These macros are dead-simple thin wrappers which delegate to other
3930
+ // traits. We only have this test to ensure that the macros are uesd
3931
+ // somewhere so our tests will break if the paths to various items
3932
+ // break.
3933
+ let x: Option < & [ u8 ; 2 ] > = try_transmute_ref ! ( & 0xFFFFu16 ) ;
3934
+ assert_eq ! ( x, Some ( & [ 255 , 255 ] ) ) ;
3935
+
3936
+ let mut u = 0xFFFFu16 ;
3937
+ let x: Option < & mut [ u8 ; 2 ] > = try_transmute_mut ! ( & mut u) ;
3938
+ assert_eq ! ( x, Some ( & mut [ 255 , 255 ] ) ) ;
3939
+ * x. unwrap ( ) = [ 0 , 0 ] ;
3940
+ assert_eq ! ( u, 0 ) ;
3716
3941
}
3717
3942
3718
3943
#[ test]
0 commit comments