@@ -209,6 +209,24 @@ macro_rules! transmute {
209209/// assert_eq!(size_of_val(src), size_of_val(dst)); 
210210/// ``` 
211211/// 
212+ /// ## `#![allow(shrink)]` 
213+ /// 
214+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports 
215+ /// transmutations that shrink the size of the referent; e.g.: 
216+ /// 
217+ /// ``` 
218+ /// # use zerocopy::transmute_ref; 
219+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
220+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
221+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src); 
222+ /// 
223+ /// assert_eq!(src.len(), 3); 
224+ /// assert_eq!(dst.len(), 4); 
225+ /// assert_eq!(size_of_val(src), 9); 
226+ /// assert_eq!(size_of_val(dst), 8); 
227+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
228+ /// ``` 
229+ /// 
212230/// # Errors 
213231/// 
214232/// Violations of the alignment and size compatibility checks are detected 
@@ -295,7 +313,18 @@ macro_rules! transmute {
295313/// `Dst: Sized`. 
296314#[ macro_export]  
297315macro_rules!  transmute_ref { 
298-     ( $e: expr)  => { { 
316+     ( #![ allow( shrink) ]  $e: expr)  => { 
317+         $crate:: __transmute_ref_inner!( true ,  $e) 
318+     } ; 
319+     ( $e: expr)  => { 
320+         $crate:: __transmute_ref_inner!( false ,  $e) 
321+     } ; 
322+ } 
323+ 
324+ #[ macro_export]  
325+ #[ doc( hidden) ]  
326+ macro_rules!  __transmute_ref_inner { 
327+     ( $allow_shrink: literal,  $e: expr)  => { { 
299328        // NOTE: This must be a macro (rather than a function with trait bounds) 
300329        // because there's no way, in a generic context, to enforce that two 
301330        // types have the same size or alignment. 
@@ -334,10 +363,10 @@ macro_rules! transmute_ref {
334363            // - `Src: IntoBytes + Immutable` 
335364            // - `Dst: FromBytes + Immutable` 
336365            unsafe  { 
337-                 t. transmute_ref( ) 
366+                 t. transmute_ref:: <$allow_shrink> ( ) 
338367            } 
339368        } 
340-     } } 
369+     } } ; 
341370} 
342371
343372/// Safely transmutes a mutable reference of one type to a mutable reference of 
@@ -383,6 +412,29 @@ macro_rules! transmute_ref {
383412/// assert_eq!(size_of_val(src), dst_size); 
384413/// ``` 
385414/// 
415+ /// ## `#![allow(shrink)]` 
416+ /// 
417+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports 
418+ /// transmutations that shrink the size of the referent; e.g.: 
419+ /// 
420+ /// ``` 
421+ /// # use zerocopy::transmute_mut; 
422+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
423+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
424+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src); 
425+ /// 
426+ /// 
427+ /// let dst_len = dst.len(); 
428+ /// let dst_size = size_of_val(dst); 
429+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
430+ /// 
431+ /// assert_eq!(src.len(), 3); 
432+ /// assert_eq!(dst_len, 4); 
433+ /// 
434+ /// assert_eq!(size_of_val(src), 9); 
435+ /// assert_eq!(dst_size, 8); 
436+ /// ``` 
437+ /// 
386438/// # Errors 
387439/// 
388440/// Violations of the alignment and size compatibility checks are detected 
@@ -471,7 +523,18 @@ macro_rules! transmute_ref {
471523/// ``` 
472524#[ macro_export]  
473525macro_rules!  transmute_mut { 
474-     ( $e: expr)  => { { 
526+     ( #![ allow( shrink) ]  $e: expr)  => { 
527+         $crate:: __transmute_mut_inner!( true ,  $e) 
528+     } ; 
529+     ( $e: expr)  => { 
530+         $crate:: __transmute_mut_inner!( false ,  $e) 
531+     } ; 
532+ } 
533+ 
534+ #[ doc( hidden) ]  
535+ #[ macro_export]  
536+ macro_rules!  __transmute_mut_inner { 
537+     ( $allow_shrink: literal,  $e: expr)  => { { 
475538        // NOTE: This must be a macro (rather than a function with trait bounds) 
476539        // because, for backwards-compatibility on v0.8.x, we use the autoref 
477540        // specialization trick to dispatch to different `transmute_mut` 
@@ -485,7 +548,7 @@ macro_rules! transmute_mut {
485548        #[ allow( unused) ] 
486549        use  $crate:: util:: macro_util:: TransmuteMutDst  as  _; 
487550        let  t = $crate:: util:: macro_util:: Wrap :: new( e) ; 
488-         t. transmute_mut( ) 
551+         t. transmute_mut:: <$allow_shrink> ( ) 
489552    } } 
490553} 
491554
@@ -1233,6 +1296,11 @@ mod tests {
12331296        let  slice_of_u16s:  & [ U16 ]  = <[ U16 ] >:: ref_from_bytes ( & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] [ ..] ) . unwrap ( ) ; 
12341297        assert_eq ! ( x,  slice_of_u16s) ; 
12351298
1299+         // Test that transmuting from a larger sized type to a smaller sized 
1300+         // type works. 
1301+         let  x:  & u8  = transmute_ref ! ( #![ allow( shrink) ]  & 0u16 ) ; 
1302+         assert_eq ! ( * x,  0 ) ; 
1303+ 
12361304        // Test that transmuting from a type with larger trailing slice offset 
12371305        // and larger trailing slice element works. 
12381306        let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
@@ -1241,6 +1309,15 @@ mod tests {
12411309        let  x:  & SliceDst < U16 ,  u8 >  = transmute_ref ! ( slice_dst_big) ; 
12421310        assert_eq ! ( x,  slice_dst_small) ; 
12431311
1312+         let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
1313+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ; 
1314+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ; 
1315+         let  x:  & SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_ref ! ( 
1316+             #![ allow( shrink) ] 
1317+             slice_dst_big
1318+         ) ; 
1319+         assert_eq ! ( x,  slice_dst_small) ; 
1320+ 
12441321        // Test that it's legal to transmute a reference while shrinking the 
12451322        // lifetime (note that `X` has the lifetime `'static`). 
12461323        let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
@@ -1421,6 +1498,14 @@ mod tests {
14211498        let  x:  & mut  [ i16 ]  = transmute_mut ! ( array_of_u16s) ; 
14221499        assert_eq ! ( x,  array_of_i16s) ; 
14231500
1501+         // Test that transmuting from a larger sized type to a smaller sized 
1502+         // type works. 
1503+         let  mut  large:  [ u8 ;  2 ]  = [ 1 ,  1 ] ; 
1504+         let  x:  & mut  u8  = transmute_mut ! ( #![ allow( shrink) ]  & mut  large) ; 
1505+         assert_eq ! ( * x,  1 ) ; 
1506+         * x = 0 ; 
1507+         assert_eq ! ( large,  [ 0 ,  1 ] ) ; 
1508+ 
14241509        // Test that transmuting from a type with larger trailing slice offset 
14251510        // and larger trailing slice element works. 
14261511        let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
@@ -1429,6 +1514,16 @@ mod tests {
14291514        let  slice_dst_small = SliceDst :: < U16 ,  u8 > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
14301515        let  x:  & mut  SliceDst < U16 ,  u8 >  = transmute_mut ! ( slice_dst_big) ; 
14311516        assert_eq ! ( x,  slice_dst_small) ; 
1517+ 
1518+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
1519+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1520+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] ; 
1521+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1522+         let  x:  & mut  SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_mut ! ( 
1523+             #![ allow( shrink) ] 
1524+             slice_dst_big
1525+         ) ; 
1526+         assert_eq ! ( x,  slice_dst_small) ; 
14321527    } 
14331528
14341529    #[ test]  
0 commit comments