@@ -208,6 +208,24 @@ macro_rules! transmute {
208208/// assert_eq!(size_of_val(src), size_of_val(dst)); 
209209/// ``` 
210210/// 
211+ /// ## `#![allow(shrink)]` 
212+ /// 
213+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports 
214+ /// transmutations that shrink the size of the referent; e.g.: 
215+ /// 
216+ /// ``` 
217+ /// # use zerocopy::transmute_ref; 
218+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
219+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
220+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src); 
221+ /// 
222+ /// assert_eq!(src.len(), 3); 
223+ /// assert_eq!(dst.len(), 4); 
224+ /// assert_eq!(size_of_val(src), 9); 
225+ /// assert_eq!(size_of_val(dst), 8); 
226+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
227+ /// ``` 
228+ /// 
211229/// # Errors 
212230/// 
213231/// Violations of the alignment and size compatibility checks are detected 
@@ -294,7 +312,18 @@ macro_rules! transmute {
294312/// `Dst: Sized`. 
295313#[ macro_export]  
296314macro_rules!  transmute_ref { 
297-     ( $e: expr)  => { { 
315+     ( #![ allow( shrink) ]  $e: expr)  => { 
316+         $crate:: __transmute_ref_inner!( true ,  $e) 
317+     } ; 
318+     ( $e: expr)  => { 
319+         $crate:: __transmute_ref_inner!( false ,  $e) 
320+     } ; 
321+ } 
322+ 
323+ #[ macro_export]  
324+ #[ doc( hidden) ]  
325+ macro_rules!  __transmute_ref_inner { 
326+     ( $allow_shrink: literal,  $e: expr)  => { { 
298327        // NOTE: This must be a macro (rather than a function with trait bounds) 
299328        // because there's no way, in a generic context, to enforce that two 
300329        // types have the same size or alignment. 
@@ -333,10 +362,10 @@ macro_rules! transmute_ref {
333362            // - `Src: IntoBytes + Immutable` 
334363            // - `Dst: FromBytes + Immutable` 
335364            unsafe  { 
336-                 t. transmute_ref( ) 
365+                 t. transmute_ref:: <$allow_shrink> ( ) 
337366            } 
338367        } 
339-     } } 
368+     } } ; 
340369} 
341370
342371/// Safely transmutes a mutable reference of one type to a mutable reference of 
@@ -382,6 +411,29 @@ macro_rules! transmute_ref {
382411/// assert_eq!(size_of_val(src), dst_size); 
383412/// ``` 
384413/// 
414+ /// ## `#![allow(shrink)]` 
415+ /// 
416+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports 
417+ /// transmutations that shrink the size of the referent; e.g.: 
418+ /// 
419+ /// ``` 
420+ /// # use zerocopy::transmute_mut; 
421+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
422+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
423+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src); 
424+ /// 
425+ /// 
426+ /// let dst_len = dst.len(); 
427+ /// let dst_size = size_of_val(dst); 
428+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
429+ /// 
430+ /// assert_eq!(src.len(), 3); 
431+ /// assert_eq!(dst_len, 4); 
432+ /// 
433+ /// assert_eq!(size_of_val(src), 9); 
434+ /// assert_eq!(dst_size, 8); 
435+ /// ``` 
436+ /// 
385437/// # Errors 
386438/// 
387439/// Violations of the alignment and size compatibility checks are detected 
@@ -470,7 +522,18 @@ macro_rules! transmute_ref {
470522/// ``` 
471523#[ macro_export]  
472524macro_rules!  transmute_mut { 
473-     ( $e: expr)  => { { 
525+     ( #![ allow( shrink) ]  $e: expr)  => { 
526+         $crate:: __transmute_mut_inner!( true ,  $e) 
527+     } ; 
528+     ( $e: expr)  => { 
529+         $crate:: __transmute_mut_inner!( false ,  $e) 
530+     } ; 
531+ } 
532+ 
533+ #[ doc( hidden) ]  
534+ #[ macro_export]  
535+ macro_rules!  __transmute_mut_inner { 
536+     ( $allow_shrink: literal,  $e: expr)  => { { 
474537        // NOTE: This must be a macro (rather than a function with trait bounds) 
475538        // because, for backwards-compatibility on v0.8.x, we use the autoref 
476539        // specialization trick to dispatch to different `transmute_mut` 
@@ -484,7 +547,7 @@ macro_rules! transmute_mut {
484547        #[ allow( unused) ] 
485548        use  $crate:: util:: macro_util:: TransmuteMutDst  as  _; 
486549        let  t = $crate:: util:: macro_util:: Wrap :: new( e) ; 
487-         t. transmute_mut( ) 
550+         t. transmute_mut:: <$allow_shrink> ( ) 
488551    } } 
489552} 
490553
@@ -1232,6 +1295,11 @@ mod tests {
12321295        let  slice_of_u16s:  & [ U16 ]  = <[ U16 ] >:: ref_from_bytes ( & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] [ ..] ) . unwrap ( ) ; 
12331296        assert_eq ! ( x,  slice_of_u16s) ; 
12341297
1298+         // Test that transmuting from a larger sized type to a smaller sized 
1299+         // type works. 
1300+         let  x:  & u8  = transmute_ref ! ( #![ allow( shrink) ]  & 0u16 ) ; 
1301+         assert_eq ! ( * x,  0 ) ; 
1302+ 
12351303        // Test that transmuting from a type with larger trailing slice offset 
12361304        // and larger trailing slice element works. 
12371305        let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
@@ -1240,6 +1308,15 @@ mod tests {
12401308        let  x:  & SliceDst < U16 ,  u8 >  = transmute_ref ! ( slice_dst_big) ; 
12411309        assert_eq ! ( x,  slice_dst_small) ; 
12421310
1311+         let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
1312+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ; 
1313+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ; 
1314+         let  x:  & SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_ref ! ( 
1315+             #![ allow( shrink) ] 
1316+             slice_dst_big
1317+         ) ; 
1318+         assert_eq ! ( x,  slice_dst_small) ; 
1319+ 
12431320        // Test that it's legal to transmute a reference while shrinking the 
12441321        // lifetime (note that `X` has the lifetime `'static`). 
12451322        let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
@@ -1420,6 +1497,14 @@ mod tests {
14201497        let  x:  & mut  [ i16 ]  = transmute_mut ! ( array_of_u16s) ; 
14211498        assert_eq ! ( x,  array_of_i16s) ; 
14221499
1500+         // Test that transmuting from a larger sized type to a smaller sized 
1501+         // type works. 
1502+         let  mut  large:  [ u8 ;  2 ]  = [ 1 ,  1 ] ; 
1503+         let  x:  & mut  u8  = transmute_mut ! ( #![ allow( shrink) ]  & mut  large) ; 
1504+         assert_eq ! ( * x,  1 ) ; 
1505+         * x = 0 ; 
1506+         assert_eq ! ( large,  [ 0 ,  1 ] ) ; 
1507+ 
14231508        // Test that transmuting from a type with larger trailing slice offset 
14241509        // and larger trailing slice element works. 
14251510        let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
@@ -1428,6 +1513,16 @@ mod tests {
14281513        let  slice_dst_small = SliceDst :: < U16 ,  u8 > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
14291514        let  x:  & mut  SliceDst < U16 ,  u8 >  = transmute_mut ! ( slice_dst_big) ; 
14301515        assert_eq ! ( x,  slice_dst_small) ; 
1516+ 
1517+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
1518+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1519+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] ; 
1520+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1521+         let  x:  & mut  SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_mut ! ( 
1522+             #![ allow( shrink) ] 
1523+             slice_dst_big
1524+         ) ; 
1525+         assert_eq ! ( x,  slice_dst_small) ; 
14311526    } 
14321527
14331528    #[ test]  
0 commit comments