@@ -179,6 +179,24 @@ macro_rules! __transmute_inner {
179179/// assert_eq!(size_of_val(src), size_of_val(dst)); 
180180/// ``` 
181181/// 
182+ /// ## `#![allow(shrink)]` 
183+ /// 
184+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports 
185+ /// transmutations that shrink the size of the referent; e.g.: 
186+ /// 
187+ /// ``` 
188+ /// # use zerocopy::transmute_ref; 
189+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
190+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
191+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src); 
192+ /// 
193+ /// assert_eq!(src.len(), 3); 
194+ /// assert_eq!(dst.len(), 4); 
195+ /// assert_eq!(size_of_val(src), 9); 
196+ /// assert_eq!(size_of_val(dst), 8); 
197+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
198+ /// ``` 
199+ /// 
182200/// # Errors 
183201/// 
184202/// Violations of the alignment and size compatibility checks are detected 
@@ -265,7 +283,18 @@ macro_rules! __transmute_inner {
265283/// `Dst: Sized`. 
266284#[ macro_export]  
267285macro_rules!  transmute_ref { 
268-     ( $e: expr)  => { { 
286+     ( #![ allow( shrink) ]  $e: expr)  => { 
287+         $crate:: __transmute_ref_inner!( true ,  $e) 
288+     } ; 
289+     ( $e: expr)  => { 
290+         $crate:: __transmute_ref_inner!( false ,  $e) 
291+     } ; 
292+ } 
293+ 
294+ #[ macro_export]  
295+ #[ doc( hidden) ]  
296+ macro_rules!  __transmute_ref_inner { 
297+     ( $allow_shrink: literal,  $e: expr)  => { { 
269298        // NOTE: This must be a macro (rather than a function with trait bounds) 
270299        // because there's no way, in a generic context, to enforce that two 
271300        // types have the same size or alignment. 
@@ -304,10 +333,10 @@ macro_rules! transmute_ref {
304333            // - `Src: IntoBytes + Immutable` 
305334            // - `Dst: FromBytes + Immutable` 
306335            unsafe  { 
307-                 t. transmute_ref( ) 
336+                 t. transmute_ref:: <$allow_shrink> ( ) 
308337            } 
309338        } 
310-     } } 
339+     } } ; 
311340} 
312341
313342/// Safely transmutes a mutable reference of one type to a mutable reference of 
@@ -353,6 +382,29 @@ macro_rules! transmute_ref {
353382/// assert_eq!(size_of_val(src), dst_size); 
354383/// ``` 
355384/// 
385+ /// ## `#![allow(shrink)]` 
386+ /// 
387+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports 
388+ /// transmutations that shrink the size of the referent; e.g.: 
389+ /// 
390+ /// ``` 
391+ /// # use zerocopy::transmute_mut; 
392+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
393+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
394+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src); 
395+ /// 
396+ /// 
397+ /// let dst_len = dst.len(); 
398+ /// let dst_size = size_of_val(dst); 
399+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
400+ /// 
401+ /// assert_eq!(src.len(), 3); 
402+ /// assert_eq!(dst_len, 4); 
403+ /// 
404+ /// assert_eq!(size_of_val(src), 9); 
405+ /// assert_eq!(dst_size, 8); 
406+ /// ``` 
407+ /// 
356408/// # Errors 
357409/// 
358410/// Violations of the alignment and size compatibility checks are detected 
@@ -441,7 +493,18 @@ macro_rules! transmute_ref {
441493/// ``` 
442494#[ macro_export]  
443495macro_rules!  transmute_mut { 
444-     ( $e: expr)  => { { 
496+     ( #![ allow( shrink) ]  $e: expr)  => { 
497+         $crate:: __transmute_mut_inner!( true ,  $e) 
498+     } ; 
499+     ( $e: expr)  => { 
500+         $crate:: __transmute_mut_inner!( false ,  $e) 
501+     } ; 
502+ } 
503+ 
504+ #[ doc( hidden) ]  
505+ #[ macro_export]  
506+ macro_rules!  __transmute_mut_inner { 
507+     ( $allow_shrink: literal,  $e: expr)  => { { 
445508        // NOTE: This must be a macro (rather than a function with trait bounds) 
446509        // because, for backwards-compatibility on v0.8.x, we use the autoref 
447510        // specialization trick to dispatch to different `transmute_mut` 
@@ -455,7 +518,7 @@ macro_rules! transmute_mut {
455518        #[ allow( unused) ] 
456519        use  $crate:: util:: macro_util:: TransmuteMutDst  as  _; 
457520        let  t = $crate:: util:: macro_util:: Wrap :: new( e) ; 
458-         t. transmute_mut( ) 
521+         t. transmute_mut:: <$allow_shrink> ( ) 
459522    } } 
460523} 
461524
@@ -1203,6 +1266,11 @@ mod tests {
12031266        let  slice_of_u16s:  & [ U16 ]  = <[ U16 ] >:: ref_from_bytes ( & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] [ ..] ) . unwrap ( ) ; 
12041267        assert_eq ! ( x,  slice_of_u16s) ; 
12051268
1269+         // Test that transmuting from a larger sized type to a smaller sized 
1270+         // type works. 
1271+         let  x:  & u8  = transmute_ref ! ( #![ allow( shrink) ]  & 0u16 ) ; 
1272+         assert_eq ! ( * x,  0 ) ; 
1273+ 
12061274        // Test that transmuting from a type with larger trailing slice offset 
12071275        // and larger trailing slice element works. 
12081276        let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
@@ -1211,6 +1279,15 @@ mod tests {
12111279        let  x:  & SliceDst < U16 ,  u8 >  = transmute_ref ! ( slice_dst_big) ; 
12121280        assert_eq ! ( x,  slice_dst_small) ; 
12131281
1282+         let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
1283+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ; 
1284+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ; 
1285+         let  x:  & SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_ref ! ( 
1286+             #![ allow( shrink) ] 
1287+             slice_dst_big
1288+         ) ; 
1289+         assert_eq ! ( x,  slice_dst_small) ; 
1290+ 
12141291        // Test that it's legal to transmute a reference while shrinking the 
12151292        // lifetime (note that `X` has the lifetime `'static`). 
12161293        let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
@@ -1391,6 +1468,14 @@ mod tests {
13911468        let  x:  & mut  [ i16 ]  = transmute_mut ! ( array_of_u16s) ; 
13921469        assert_eq ! ( x,  array_of_i16s) ; 
13931470
1471+         // Test that transmuting from a larger sized type to a smaller sized 
1472+         // type works. 
1473+         let  mut  large:  [ u8 ;  2 ]  = [ 1 ,  1 ] ; 
1474+         let  x:  & mut  u8  = transmute_mut ! ( #![ allow( shrink) ]  & mut  large) ; 
1475+         assert_eq ! ( * x,  1 ) ; 
1476+         * x = 0 ; 
1477+         assert_eq ! ( large,  [ 0 ,  1 ] ) ; 
1478+ 
13941479        // Test that transmuting from a type with larger trailing slice offset 
13951480        // and larger trailing slice element works. 
13961481        let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
@@ -1399,6 +1484,16 @@ mod tests {
13991484        let  slice_dst_small = SliceDst :: < U16 ,  u8 > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
14001485        let  x:  & mut  SliceDst < U16 ,  u8 >  = transmute_mut ! ( slice_dst_big) ; 
14011486        assert_eq ! ( x,  slice_dst_small) ; 
1487+ 
1488+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
1489+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1490+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] ; 
1491+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1492+         let  x:  & mut  SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_mut ! ( 
1493+             #![ allow( shrink) ] 
1494+             slice_dst_big
1495+         ) ; 
1496+         assert_eq ! ( x,  slice_dst_small) ; 
14021497    } 
14031498
14041499    #[ test]  
0 commit comments