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