@@ -185,6 +185,24 @@ macro_rules! transmute {
185185/// assert_eq!(size_of_val(src), size_of_val(dst)); 
186186/// ``` 
187187/// 
188+ /// ## `#![allow(shrink)]` 
189+ /// 
190+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports 
191+ /// transmutations that shrink the size of the referent; e.g.: 
192+ /// 
193+ /// ``` 
194+ /// # use zerocopy::transmute_ref; 
195+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
196+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
197+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src); 
198+ /// 
199+ /// assert_eq!(src.len(), 3); 
200+ /// assert_eq!(dst.len(), 4); 
201+ /// assert_eq!(size_of_val(src), 9); 
202+ /// assert_eq!(size_of_val(dst), 8); 
203+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
204+ /// ``` 
205+ /// 
188206/// # Errors 
189207/// 
190208/// Violations of the alignment and size compatibility checks are detected 
@@ -271,7 +289,18 @@ macro_rules! transmute {
271289/// `Dst: Sized`. 
272290#[ macro_export]  
273291macro_rules!  transmute_ref { 
274-     ( $e: expr)  => { { 
292+     ( #![ allow( shrink) ]  $e: expr)  => { 
293+         $crate:: __transmute_ref_inner!( true ,  $e) 
294+     } ; 
295+     ( $e: expr)  => { 
296+         $crate:: __transmute_ref_inner!( false ,  $e) 
297+     } ; 
298+ } 
299+ 
300+ #[ macro_export]  
301+ #[ doc( hidden) ]  
302+ macro_rules!  __transmute_ref_inner { 
303+     ( $allow_shrink: literal,  $e: expr)  => { { 
275304        // NOTE: This must be a macro (rather than a function with trait bounds) 
276305        // because there's no way, in a generic context, to enforce that two 
277306        // types have the same size or alignment. 
@@ -310,10 +339,10 @@ macro_rules! transmute_ref {
310339            // - `Src: IntoBytes + Immutable` 
311340            // - `Dst: FromBytes + Immutable` 
312341            unsafe  { 
313-                 t. transmute_ref( ) 
342+                 t. transmute_ref:: <$allow_shrink> ( ) 
314343            } 
315344        } 
316-     } } 
345+     } } ; 
317346} 
318347
319348/// Safely transmutes a mutable reference of one type to a mutable reference of 
@@ -359,6 +388,29 @@ macro_rules! transmute_ref {
359388/// assert_eq!(size_of_val(src), dst_size); 
360389/// ``` 
361390/// 
391+ /// ## `#![allow(shrink)]` 
392+ /// 
393+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports 
394+ /// transmutations that shrink the size of the referent; e.g.: 
395+ /// 
396+ /// ``` 
397+ /// # use zerocopy::transmute_mut; 
398+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
399+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
400+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src); 
401+ /// 
402+ /// 
403+ /// let dst_len = dst.len(); 
404+ /// let dst_size = size_of_val(dst); 
405+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
406+ /// 
407+ /// assert_eq!(src.len(), 3); 
408+ /// assert_eq!(dst_len, 4); 
409+ /// 
410+ /// assert_eq!(size_of_val(src), 9); 
411+ /// assert_eq!(dst_size, 8); 
412+ /// ``` 
413+ /// 
362414/// # Errors 
363415/// 
364416/// Violations of the alignment and size compatibility checks are detected 
@@ -447,7 +499,18 @@ macro_rules! transmute_ref {
447499/// ``` 
448500#[ macro_export]  
449501macro_rules!  transmute_mut { 
450-     ( $e: expr)  => { { 
502+     ( #![ allow( shrink) ]  $e: expr)  => { 
503+         $crate:: __transmute_mut_inner!( true ,  $e) 
504+     } ; 
505+     ( $e: expr)  => { 
506+         $crate:: __transmute_mut_inner!( false ,  $e) 
507+     } ; 
508+ } 
509+ 
510+ #[ doc( hidden) ]  
511+ #[ macro_export]  
512+ macro_rules!  __transmute_mut_inner { 
513+     ( $allow_shrink: literal,  $e: expr)  => { { 
451514        // NOTE: This must be a macro (rather than a function with trait bounds) 
452515        // because, for backwards-compatibility on v0.8.x, we use the autoref 
453516        // specialization trick to dispatch to different `transmute_mut` 
@@ -461,7 +524,7 @@ macro_rules! transmute_mut {
461524        #[ allow( unused) ] 
462525        use  $crate:: util:: macro_util:: TransmuteMutDst  as  _; 
463526        let  t = $crate:: util:: macro_util:: Wrap :: new( e) ; 
464-         t. transmute_mut( ) 
527+         t. transmute_mut:: <$allow_shrink> ( ) 
465528    } } 
466529} 
467530
@@ -1209,6 +1272,11 @@ mod tests {
12091272        let  slice_of_u16s:  & [ U16 ]  = <[ U16 ] >:: ref_from_bytes ( & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] [ ..] ) . unwrap ( ) ; 
12101273        assert_eq ! ( x,  slice_of_u16s) ; 
12111274
1275+         // Test that transmuting from a larger sized type to a smaller sized 
1276+         // type works. 
1277+         let  x:  & u8  = transmute_ref ! ( #![ allow( shrink) ]  & 0u16 ) ; 
1278+         assert_eq ! ( * x,  0 ) ; 
1279+ 
12121280        // Test that transmuting from a type with larger trailing slice offset 
12131281        // and larger trailing slice element works. 
12141282        let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
@@ -1217,6 +1285,15 @@ mod tests {
12171285        let  x:  & SliceDst < U16 ,  u8 >  = transmute_ref ! ( slice_dst_big) ; 
12181286        assert_eq ! ( x,  slice_dst_small) ; 
12191287
1288+         let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
1289+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ; 
1290+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ; 
1291+         let  x:  & SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_ref ! ( 
1292+             #![ allow( shrink) ] 
1293+             slice_dst_big
1294+         ) ; 
1295+         assert_eq ! ( x,  slice_dst_small) ; 
1296+ 
12201297        // Test that it's legal to transmute a reference while shrinking the 
12211298        // lifetime (note that `X` has the lifetime `'static`). 
12221299        let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
@@ -1397,6 +1474,14 @@ mod tests {
13971474        let  x:  & mut  [ i16 ]  = transmute_mut ! ( array_of_u16s) ; 
13981475        assert_eq ! ( x,  array_of_i16s) ; 
13991476
1477+         // Test that transmuting from a larger sized type to a smaller sized 
1478+         // type works. 
1479+         let  mut  large:  [ u8 ;  2 ]  = [ 1 ,  1 ] ; 
1480+         let  x:  & mut  u8  = transmute_mut ! ( #![ allow( shrink) ]  & mut  large) ; 
1481+         assert_eq ! ( * x,  1 ) ; 
1482+         * x = 0 ; 
1483+         assert_eq ! ( large,  [ 0 ,  1 ] ) ; 
1484+ 
14001485        // Test that transmuting from a type with larger trailing slice offset 
14011486        // and larger trailing slice element works. 
14021487        let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
@@ -1405,6 +1490,16 @@ mod tests {
14051490        let  slice_dst_small = SliceDst :: < U16 ,  u8 > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
14061491        let  x:  & mut  SliceDst < U16 ,  u8 >  = transmute_mut ! ( slice_dst_big) ; 
14071492        assert_eq ! ( x,  slice_dst_small) ; 
1493+ 
1494+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
1495+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1496+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] ; 
1497+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1498+         let  x:  & mut  SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_mut ! ( 
1499+             #![ allow( shrink) ] 
1500+             slice_dst_big
1501+         ) ; 
1502+         assert_eq ! ( x,  slice_dst_small) ; 
14081503    } 
14091504
14101505    #[ test]  
0 commit comments