3535/// original `Src` will be forgotten, and the value of type `Dst` will be 
3636/// returned. 
3737/// 
38+ /// # `#![allow(shrink)]` 
39+ /// 
40+ /// If `#![allow(shrink)]` is provided, `transmute!` additionally supports 
41+ /// transmutations that shrink the size of the referent; e.g.: 
42+ /// 
43+ /// ``` 
44+ /// # use zerocopy::transmute; 
45+ /// let u: u32 = transmute!(#![allow(shrink)] 0u64); 
46+ /// assert_eq!(u, 0u32); 
47+ /// ``` 
48+ /// 
3849/// # Examples 
3950/// 
4051/// ``` 
4960/// # Use in `const` contexts 
5061/// 
5162/// This macro can be invoked in `const` contexts. 
63+ // TODO: Update docs to document `#![allow(shrink)]` 
5264#[ macro_export]  
5365macro_rules!  transmute { 
54-     ( $e: expr)  => { { 
55-         // NOTE: This must be a macro (rather than a function with trait bounds) 
56-         // because there's no way, in a generic context, to enforce that two 
57-         // types have the same size. `core::mem::transmute` uses compiler magic 
58-         // to enforce this so long as the types are concrete. 
66+     // NOTE: This must be a macro (rather than a function with trait bounds) 
67+     // because there's no way, in a generic context, to enforce that two types 
68+     // have the same size. `core::mem::transmute` uses compiler magic to enforce 
69+     // this so long as the types are concrete. 
70+     ( #![ allow( shrink) ]  $e: expr)  => { { 
71+         let  mut  e = $e; 
72+         if  false  { 
73+             // This branch, though never taken, ensures that the type of `e` is 
74+             // `IntoBytes` and that the type of the  outer macro invocation 
75+             // expression is `FromBytes`. 
76+ 
77+             fn  transmute<Src ,  Dst >( src:  Src )  -> Dst 
78+             where 
79+                 Src :  $crate:: IntoBytes , 
80+                 Dst :  $crate:: FromBytes , 
81+             { 
82+                 let  _ = src; 
83+                 loop  { } 
84+             } 
85+             loop  { } 
86+             #[ allow( unreachable_code) ] 
87+             transmute( e) 
88+         }  else { 
89+             use  $crate:: util:: macro_util:: core_reexport:: mem:: ManuallyDrop ; 
5990
91+             #[ repr( C ,  packed) ] 
92+             union  Transmute <Src ,  Dst > { 
93+                 src:  ManuallyDrop <Src >, 
94+                 dst:  ManuallyDrop <Dst >, 
95+             } 
96+ 
97+             // SAFETY: `Transmute` is a `reper(C)` union whose `src` field has 
98+             // type `ManuallyDrop<Src>`. Thus, the `src` field starts at byte 
99+             // offset 0 within `Transmute` [1]. `ManuallyDrop<T>` has the same 
100+             // layout and bit validity as `T`, so it is sound to transmute `Src` 
101+             // to `Transmute`. 
102+             // 
103+             // [1] https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions 
104+             // 
105+             // [2] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: 
106+             // 
107+             //   `ManuallyDrop<T>` is guaranteed to have the same layout and bit 
108+             //   validity as `T` 
109+             let  u:  Transmute <_,  _> = unsafe  { 
110+                 // Clippy: We can't annotate the types; this macro is designed 
111+                 // to infer the types from the calling context. 
112+                 #[ allow( clippy:: missing_transmute_annotations) ] 
113+                 $crate:: util:: macro_util:: core_reexport:: mem:: transmute( e) 
114+             } ; 
115+ 
116+             if  false  { 
117+                 // SAFETY: This code is never executed. 
118+                 e = ManuallyDrop :: into_inner( unsafe  {  u. src } ) ; 
119+                 // Suppress the `unused_assignments` lint on the previous line. 
120+                 let  _ = e; 
121+                 loop  { } 
122+             }  else { 
123+                 // Per the safety comment on `let u` above, the `dst` field in 
124+                 // `Transmute` starts at byte offset 0, and has the same layout 
125+                 // and bit validity as `Dst`. 
126+                 // 
127+                 // Transmuting `Src` to `Transmute<Src, Dst>` above using 
128+                 // `core::mem::transmute` ensures that `size_of::<Src>() == 
129+                 // size_of::<Transmute<Src, Dst>>()`. A `#[repr(C, packed)]` 
130+                 // union has the maximum size of all of its fields [1], so this 
131+                 // is equivalent to `size_of::<Src>() >= size_of::<Dst>()`. 
132+                 // 
133+                 // The outer `if`'s `false` branch ensures that `Src: IntoBytes` 
134+                 // and `Dst: FromBytes`. This, combined with the size bound, 
135+                 // ensures that this transmute is sound. 
136+                 // 
137+                 // Per https://doc.rust-lang.org/1.85.0/reference/type-layout.html#reprc-unions: 
138+                 // 
139+                 //   The union will have a size of the maximum size of all of 
140+                 //   its fields rounded to its alignment 
141+                 let  dst = unsafe  {  u. dst } ; 
142+                 $crate:: util:: macro_util:: must_use( ManuallyDrop :: into_inner( dst) ) 
143+             } 
144+         } 
145+     } } ; 
146+     ( $e: expr)  => { { 
60147        let  e = $e; 
61148        if  false  { 
62149            // This branch, though never taken, ensures that the type of `e` is 
63-             // `IntoBytes` and that the type of this macro invocation expression 
64-             // is `FromBytes`. 
65- 
66-             struct  AssertIsIntoBytes <T :  $crate:: IntoBytes >( T ) ; 
67-             let  _ = AssertIsIntoBytes ( e) ; 
150+             // `IntoBytes` and that the type of the  outer macro invocation 
151+             // expression is `FromBytes`. 
68152
69-             struct  AssertIsFromBytes <U :  $crate:: FromBytes >( U ) ; 
70-             #[ allow( unused,  unreachable_code) ] 
71-             let  u = AssertIsFromBytes ( loop  { } ) ; 
72-             u. 0 
153+             fn  transmute<Src ,  Dst >( src:  Src )  -> Dst 
154+             where 
155+                 Src :  $crate:: IntoBytes , 
156+                 Dst :  $crate:: FromBytes , 
157+             { 
158+                 let  _ = src; 
159+                 loop  { } 
160+             } 
161+             loop  { } 
162+             #[ allow( unreachable_code) ] 
163+             transmute( e) 
73164        }  else { 
74165            // SAFETY: `core::mem::transmute` ensures that the type of `e` and 
75166            // the type of this macro invocation expression have the same size. 
76167            // We know this transmute is safe thanks to the `IntoBytes` and 
77168            // `FromBytes` bounds enforced by the `false` branch. 
78-             // 
79-             // We use this reexport of `core::mem::transmute` because we know it 
80-             // will always be available for crates which are using the 2015 
81-             // edition of Rust. By contrast, if we were to use 
82-             // `std::mem::transmute`, this macro would not work for such crates 
83-             // in `no_std` contexts, and if we were to use 
84-             // `core::mem::transmute`, this macro would not work in `std` 
85-             // contexts in which `core` was not manually imported. This is not a 
86-             // problem for 2018 edition crates. 
87169            let  u = unsafe  { 
88170                // Clippy: We can't annotate the types; this macro is designed 
89171                // to infer the types from the calling context. 
@@ -92,7 +174,7 @@ macro_rules! transmute {
92174            } ; 
93175            $crate:: util:: macro_util:: must_use( u) 
94176        } 
95-     } } 
177+     } } ; 
96178} 
97179
98180/// Safely transmutes a mutable or immutable reference of one type to an 
@@ -1046,6 +1128,10 @@ mod tests {
10461128        let  x:  [ u8 ;  8 ]  = transmute ! ( array_of_arrays) ; 
10471129        assert_eq ! ( x,  array_of_u8s) ; 
10481130
1131+         // Test that memory is transmuted as expected when shrinking. 
1132+         let  x:  [ [ u8 ;  2 ] ;  3 ]  = transmute ! ( #![ allow( shrink) ]  array_of_u8s) ; 
1133+         assert_eq ! ( x,  [ [ 0u8 ,  1 ] ,  [ 2 ,  3 ] ,  [ 4 ,  5 ] ] ) ; 
1134+ 
10491135        // Test that the source expression's value is forgotten rather than 
10501136        // dropped. 
10511137        #[ derive( IntoBytes ) ]  
@@ -1058,12 +1144,16 @@ mod tests {
10581144        } 
10591145        #[ allow( clippy:: let_unit_value) ]  
10601146        let  _:  ( )  = transmute ! ( PanicOnDrop ( ( ) ) ) ; 
1147+         #[ allow( clippy:: let_unit_value) ]  
1148+         let  _:  ( )  = transmute ! ( #![ allow( shrink) ]  PanicOnDrop ( ( ) ) ) ; 
10611149
10621150        // Test that `transmute!` is legal in a const context. 
10631151        const  ARRAY_OF_U8S :  [ u8 ;  8 ]  = [ 0u8 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
10641152        const  ARRAY_OF_ARRAYS :  [ [ u8 ;  2 ] ;  4 ]  = [ [ 0 ,  1 ] ,  [ 2 ,  3 ] ,  [ 4 ,  5 ] ,  [ 6 ,  7 ] ] ; 
10651153        const  X :  [ [ u8 ;  2 ] ;  4 ]  = transmute ! ( ARRAY_OF_U8S ) ; 
10661154        assert_eq ! ( X ,  ARRAY_OF_ARRAYS ) ; 
1155+         const  X_SHRINK :  [ [ u8 ;  2 ] ;  3 ]  = transmute ! ( #![ allow( shrink) ]  ARRAY_OF_U8S ) ; 
1156+         assert_eq ! ( X_SHRINK ,  [ [ 0u8 ,  1 ] ,  [ 2 ,  3 ] ,  [ 4 ,  5 ] ] ) ; 
10671157
10681158        // Test that `transmute!` works with `!Immutable` types. 
10691159        let  x:  usize  = transmute ! ( UnsafeCell :: new( 1usize ) ) ; 
0 commit comments