@@ -219,6 +219,24 @@ macro_rules! transmute {
219219/// assert_eq!(size_of_val(src), size_of_val(dst)); 
220220/// ``` 
221221/// 
222+ /// ## `#![allow(shrink)]` 
223+ /// 
224+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports 
225+ /// transmutations that shrink the size of the referent; e.g.: 
226+ /// 
227+ /// ``` 
228+ /// # use zerocopy::transmute_ref; 
229+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
230+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
231+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src); 
232+ /// 
233+ /// assert_eq!(src.len(), 3); 
234+ /// assert_eq!(dst.len(), 4); 
235+ /// assert_eq!(size_of_val(src), 9); 
236+ /// assert_eq!(size_of_val(dst), 8); 
237+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
238+ /// ``` 
239+ /// 
222240/// # Errors 
223241/// 
224242/// Violations of the alignment and size compatibility checks are detected 
@@ -305,7 +323,18 @@ macro_rules! transmute {
305323/// `Dst: Sized`. 
306324#[ macro_export]  
307325macro_rules!  transmute_ref { 
308-     ( $e: expr)  => { { 
326+     ( #![ allow( shrink) ]  $e: expr)  => { 
327+         $crate:: __transmute_ref_inner!( true ,  $e) 
328+     } ; 
329+     ( $e: expr)  => { 
330+         $crate:: __transmute_ref_inner!( false ,  $e) 
331+     } ; 
332+ } 
333+ 
334+ #[ macro_export]  
335+ #[ doc( hidden) ]  
336+ macro_rules!  __transmute_ref_inner { 
337+     ( $allow_shrink: literal,  $e: expr)  => { { 
309338        // NOTE: This must be a macro (rather than a function with trait bounds) 
310339        // because there's no way, in a generic context, to enforce that two 
311340        // types have the same size or alignment. 
@@ -344,10 +373,10 @@ macro_rules! transmute_ref {
344373            // - `Src: IntoBytes + Immutable` 
345374            // - `Dst: FromBytes + Immutable` 
346375            unsafe  { 
347-                 t. transmute_ref( ) 
376+                 t. transmute_ref:: <$allow_shrink> ( ) 
348377            } 
349378        } 
350-     } } 
379+     } } ; 
351380} 
352381
353382/// Safely transmutes a mutable reference of one type to a mutable reference of 
@@ -393,6 +422,29 @@ macro_rules! transmute_ref {
393422/// assert_eq!(size_of_val(src), dst_size); 
394423/// ``` 
395424/// 
425+ /// ## `#![allow(shrink)]` 
426+ /// 
427+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports 
428+ /// transmutations that shrink the size of the referent; e.g.: 
429+ /// 
430+ /// ``` 
431+ /// # use zerocopy::transmute_mut; 
432+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
433+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
434+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src); 
435+ /// 
436+ /// 
437+ /// let dst_len = dst.len(); 
438+ /// let dst_size = size_of_val(dst); 
439+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
440+ /// 
441+ /// assert_eq!(src.len(), 3); 
442+ /// assert_eq!(dst_len, 4); 
443+ /// 
444+ /// assert_eq!(size_of_val(src), 9); 
445+ /// assert_eq!(dst_size, 8); 
446+ /// ``` 
447+ /// 
396448/// # Errors 
397449/// 
398450/// Violations of the alignment and size compatibility checks are detected 
@@ -481,7 +533,18 @@ macro_rules! transmute_ref {
481533/// ``` 
482534#[ macro_export]  
483535macro_rules!  transmute_mut { 
484-     ( $e: expr)  => { { 
536+     ( #![ allow( shrink) ]  $e: expr)  => { 
537+         $crate:: __transmute_mut_inner!( true ,  $e) 
538+     } ; 
539+     ( $e: expr)  => { 
540+         $crate:: __transmute_mut_inner!( false ,  $e) 
541+     } ; 
542+ } 
543+ 
544+ #[ doc( hidden) ]  
545+ #[ macro_export]  
546+ macro_rules!  __transmute_mut_inner { 
547+     ( $allow_shrink: literal,  $e: expr)  => { { 
485548        // NOTE: This must be a macro (rather than a function with trait bounds) 
486549        // because, for backwards-compatibility on v0.8.x, we use the autoref 
487550        // specialization trick to dispatch to different `transmute_mut` 
@@ -495,7 +558,7 @@ macro_rules! transmute_mut {
495558        #[ allow( unused) ] 
496559        use  $crate:: util:: macro_util:: TransmuteMutDst  as  _; 
497560        let  t = $crate:: util:: macro_util:: Wrap :: new( e) ; 
498-         t. transmute_mut( ) 
561+         t. transmute_mut:: <$allow_shrink> ( ) 
499562    } } 
500563} 
501564
@@ -1243,6 +1306,11 @@ mod tests {
12431306        let  slice_of_u16s:  & [ U16 ]  = <[ U16 ] >:: ref_from_bytes ( & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] [ ..] ) . unwrap ( ) ; 
12441307        assert_eq ! ( x,  slice_of_u16s) ; 
12451308
1309+         // Test that transmuting from a larger sized type to a smaller sized 
1310+         // type works. 
1311+         let  x:  & u8  = transmute_ref ! ( #![ allow( shrink) ]  & 0u16 ) ; 
1312+         assert_eq ! ( * x,  0 ) ; 
1313+ 
12461314        // Test that transmuting from a type with larger trailing slice offset 
12471315        // and larger trailing slice element works. 
12481316        let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
@@ -1251,6 +1319,15 @@ mod tests {
12511319        let  x:  & SliceDst < U16 ,  u8 >  = transmute_ref ! ( slice_dst_big) ; 
12521320        assert_eq ! ( x,  slice_dst_small) ; 
12531321
1322+         let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
1323+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ; 
1324+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ; 
1325+         let  x:  & SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_ref ! ( 
1326+             #![ allow( shrink) ] 
1327+             slice_dst_big
1328+         ) ; 
1329+         assert_eq ! ( x,  slice_dst_small) ; 
1330+ 
12541331        // Test that it's legal to transmute a reference while shrinking the 
12551332        // lifetime (note that `X` has the lifetime `'static`). 
12561333        let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
@@ -1431,6 +1508,14 @@ mod tests {
14311508        let  x:  & mut  [ i16 ]  = transmute_mut ! ( array_of_u16s) ; 
14321509        assert_eq ! ( x,  array_of_i16s) ; 
14331510
1511+         // Test that transmuting from a larger sized type to a smaller sized 
1512+         // type works. 
1513+         let  mut  large:  [ u8 ;  2 ]  = [ 1 ,  1 ] ; 
1514+         let  x:  & mut  u8  = transmute_mut ! ( #![ allow( shrink) ]  & mut  large) ; 
1515+         assert_eq ! ( * x,  1 ) ; 
1516+         * x = 0 ; 
1517+         assert_eq ! ( large,  [ 0 ,  1 ] ) ; 
1518+ 
14341519        // Test that transmuting from a type with larger trailing slice offset 
14351520        // and larger trailing slice element works. 
14361521        let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
@@ -1439,6 +1524,16 @@ mod tests {
14391524        let  slice_dst_small = SliceDst :: < U16 ,  u8 > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
14401525        let  x:  & mut  SliceDst < U16 ,  u8 >  = transmute_mut ! ( slice_dst_big) ; 
14411526        assert_eq ! ( x,  slice_dst_small) ; 
1527+ 
1528+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
1529+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1530+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] ; 
1531+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1532+         let  x:  & mut  SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_mut ! ( 
1533+             #![ allow( shrink) ] 
1534+             slice_dst_big
1535+         ) ; 
1536+         assert_eq ! ( x,  slice_dst_small) ; 
14421537    } 
14431538
14441539    #[ test]  
0 commit comments