@@ -138,6 +138,24 @@ macro_rules! transmute {
138138/// assert_eq!(size_of_val(src), size_of_val(dst)); 
139139/// ``` 
140140/// 
141+ /// ## `#![allow(shrink)]` 
142+ /// 
143+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports 
144+ /// transmutations that shrink the size of the referent; e.g.: 
145+ /// 
146+ /// ``` 
147+ /// # use zerocopy::transmute_ref; 
148+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
149+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
150+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src); 
151+ /// 
152+ /// assert_eq!(src.len(), 3); 
153+ /// assert_eq!(dst.len(), 4); 
154+ /// assert_eq!(size_of_val(src), 9); 
155+ /// assert_eq!(size_of_val(dst), 8); 
156+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
157+ /// ``` 
158+ /// 
141159/// # Errors 
142160/// 
143161/// Violations of the alignment and size compatibility checks are detected 
@@ -224,7 +242,18 @@ macro_rules! transmute {
224242/// `Dst: Sized`. 
225243#[ macro_export]  
226244macro_rules!  transmute_ref { 
227-     ( $e: expr)  => { { 
245+     ( #![ allow( shrink) ]  $e: expr)  => { 
246+         $crate:: __transmute_ref_inner!( true ,  $e) 
247+     } ; 
248+     ( $e: expr)  => { 
249+         $crate:: __transmute_ref_inner!( false ,  $e) 
250+     } ; 
251+ } 
252+ 
253+ #[ macro_export]  
254+ #[ doc( hidden) ]  
255+ macro_rules!  __transmute_ref_inner { 
256+     ( $allow_shrink: literal,  $e: expr)  => { { 
228257        // NOTE: This must be a macro (rather than a function with trait bounds) 
229258        // because there's no way, in a generic context, to enforce that two 
230259        // types have the same size or alignment. 
@@ -263,10 +292,10 @@ macro_rules! transmute_ref {
263292            // - `Src: IntoBytes + Immutable` 
264293            // - `Dst: FromBytes + Immutable` 
265294            unsafe  { 
266-                 t. transmute_ref( ) 
295+                 t. transmute_ref:: <$allow_shrink> ( ) 
267296            } 
268297        } 
269-     } } 
298+     } } ; 
270299} 
271300
272301/// Safely transmutes a mutable reference of one type to a mutable reference of 
@@ -312,6 +341,29 @@ macro_rules! transmute_ref {
312341/// assert_eq!(size_of_val(src), dst_size); 
313342/// ``` 
314343/// 
344+ /// ## `#![allow(shrink)]` 
345+ /// 
346+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports 
347+ /// transmutations that shrink the size of the referent; e.g.: 
348+ /// 
349+ /// ``` 
350+ /// # use zerocopy::transmute_mut; 
351+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV 
352+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..]; 
353+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src); 
354+ /// 
355+ /// 
356+ /// let dst_len = dst.len(); 
357+ /// let dst_size = size_of_val(dst); 
358+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]); 
359+ /// 
360+ /// assert_eq!(src.len(), 3); 
361+ /// assert_eq!(dst_len, 4); 
362+ /// 
363+ /// assert_eq!(size_of_val(src), 9); 
364+ /// assert_eq!(dst_size, 8); 
365+ /// ``` 
366+ /// 
315367/// # Errors 
316368/// 
317369/// Violations of the alignment and size compatibility checks are detected 
@@ -400,7 +452,18 @@ macro_rules! transmute_ref {
400452/// ``` 
401453#[ macro_export]  
402454macro_rules!  transmute_mut { 
403-     ( $e: expr)  => { { 
455+     ( #![ allow( shrink) ]  $e: expr)  => { 
456+         $crate:: __transmute_mut_inner!( true ,  $e) 
457+     } ; 
458+     ( $e: expr)  => { 
459+         $crate:: __transmute_mut_inner!( false ,  $e) 
460+     } ; 
461+ } 
462+ 
463+ #[ doc( hidden) ]  
464+ #[ macro_export]  
465+ macro_rules!  __transmute_mut_inner { 
466+     ( $allow_shrink: literal,  $e: expr)  => { { 
404467        // NOTE: This must be a macro (rather than a function with trait bounds) 
405468        // because, for backwards-compatibility on v0.8.x, we use the autoref 
406469        // specialization trick to dispatch to different `transmute_mut` 
@@ -414,7 +477,7 @@ macro_rules! transmute_mut {
414477        #[ allow( unused) ] 
415478        use  $crate:: util:: macro_util:: TransmuteMutDst  as  _; 
416479        let  t = $crate:: util:: macro_util:: Wrap :: new( e) ; 
417-         t. transmute_mut( ) 
480+         t. transmute_mut:: <$allow_shrink> ( ) 
418481    } } 
419482} 
420483
@@ -1154,6 +1217,11 @@ mod tests {
11541217        let  slice_of_u16s:  & [ U16 ]  = <[ U16 ] >:: ref_from_bytes ( & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] [ ..] ) . unwrap ( ) ; 
11551218        assert_eq ! ( x,  slice_of_u16s) ; 
11561219
1220+         // Test that transmuting from a larger sized type to a smaller sized 
1221+         // type works. 
1222+         let  x:  & u8  = transmute_ref ! ( #![ allow( shrink) ]  & 0u16 ) ; 
1223+         assert_eq ! ( * x,  0 ) ; 
1224+ 
11571225        // Test that transmuting from a type with larger trailing slice offset 
11581226        // and larger trailing slice element works. 
11591227        let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
@@ -1162,6 +1230,15 @@ mod tests {
11621230        let  x:  & SliceDst < U16 ,  u8 >  = transmute_ref ! ( slice_dst_big) ; 
11631231        assert_eq ! ( x,  slice_dst_small) ; 
11641232
1233+         let  bytes = & [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] [ ..] ; 
1234+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ; 
1235+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ; 
1236+         let  x:  & SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_ref ! ( 
1237+             #![ allow( shrink) ] 
1238+             slice_dst_big
1239+         ) ; 
1240+         assert_eq ! ( x,  slice_dst_small) ; 
1241+ 
11651242        // Test that it's legal to transmute a reference while shrinking the 
11661243        // lifetime (note that `X` has the lifetime `'static`). 
11671244        let  x:  & [ u8 ;  8 ]  = transmute_ref ! ( X ) ; 
@@ -1342,6 +1419,14 @@ mod tests {
13421419        let  x:  & mut  [ i16 ]  = transmute_mut ! ( array_of_u16s) ; 
13431420        assert_eq ! ( x,  array_of_i16s) ; 
13441421
1422+         // Test that transmuting from a larger sized type to a smaller sized 
1423+         // type works. 
1424+         let  mut  large:  [ u8 ;  2 ]  = [ 1 ,  1 ] ; 
1425+         let  x:  & mut  u8  = transmute_mut ! ( #![ allow( shrink) ]  & mut  large) ; 
1426+         assert_eq ! ( * x,  1 ) ; 
1427+         * x = 0 ; 
1428+         assert_eq ! ( large,  [ 0 ,  1 ] ) ; 
1429+ 
13451430        // Test that transmuting from a type with larger trailing slice offset 
13461431        // and larger trailing slice element works. 
13471432        let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
@@ -1350,6 +1435,16 @@ mod tests {
13501435        let  slice_dst_small = SliceDst :: < U16 ,  u8 > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
13511436        let  x:  & mut  SliceDst < U16 ,  u8 >  = transmute_mut ! ( slice_dst_big) ; 
13521437        assert_eq ! ( x,  slice_dst_small) ; 
1438+ 
1439+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ] ; 
1440+         let  slice_dst_big = SliceDst :: < [ u8 ;  4 ] ,  [ u8 ;  4 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1441+         let  mut  bytes = [ 0 ,  1 ,  2 ,  3 ,  4 ,  5 ] ; 
1442+         let  slice_dst_small = SliceDst :: < [ u8 ;  3 ] ,  [ u8 ;  3 ] > :: mut_from_bytes ( & mut  bytes[ ..] ) . unwrap ( ) ; 
1443+         let  x:  & mut  SliceDst < [ u8 ;  3 ] ,  [ u8 ;  3 ] >  = transmute_mut ! ( 
1444+             #![ allow( shrink) ] 
1445+             slice_dst_big
1446+         ) ; 
1447+         assert_eq ! ( x,  slice_dst_small) ; 
13531448    } 
13541449
13551450    #[ test]  
0 commit comments