@@ -179,6 +179,24 @@ macro_rules! __transmute_inner {
179
179
/// assert_eq!(size_of_val(src), size_of_val(dst));
180
180
/// ```
181
181
///
182
+ /// ## `#![allow(shrink)]`
183
+ ///
184
+ /// If `#![allow(shrink)]` is provided, `transmute_ref!` additionally supports
185
+ /// transmutations that shrink the size of the referent; e.g.:
186
+ ///
187
+ /// ```
188
+ /// # use zerocopy::transmute_ref;
189
+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV
190
+ /// let src: &[[u8; 3]] = &[[0, 1, 2], [3, 4, 5], [6, 7, 8]][..];
191
+ /// let dst: &[[u8; 2]] = transmute_ref!(#![allow(shrink)] src);
192
+ ///
193
+ /// assert_eq!(src.len(), 3);
194
+ /// assert_eq!(dst.len(), 4);
195
+ /// assert_eq!(size_of_val(src), 9);
196
+ /// assert_eq!(size_of_val(dst), 8);
197
+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]);
198
+ /// ```
199
+ ///
182
200
/// # Errors
183
201
///
184
202
/// Violations of the alignment and size compatibility checks are detected
@@ -265,7 +283,18 @@ macro_rules! __transmute_inner {
265
283
/// `Dst: Sized`.
266
284
#[ macro_export]
267
285
macro_rules! transmute_ref {
268
- ( $e: expr) => { {
286
+ ( #![ allow( shrink) ] $e: expr) => {
287
+ $crate:: __transmute_ref_inner!( true , $e)
288
+ } ;
289
+ ( $e: expr) => {
290
+ $crate:: __transmute_ref_inner!( false , $e)
291
+ } ;
292
+ }
293
+
294
+ #[ macro_export]
295
+ #[ doc( hidden) ]
296
+ macro_rules! __transmute_ref_inner {
297
+ ( $allow_shrink: literal, $e: expr) => { {
269
298
// NOTE: This must be a macro (rather than a function with trait bounds)
270
299
// because there's no way, in a generic context, to enforce that two
271
300
// types have the same size or alignment.
@@ -304,10 +333,10 @@ macro_rules! transmute_ref {
304
333
// - `Src: IntoBytes + Immutable`
305
334
// - `Dst: FromBytes + Immutable`
306
335
unsafe {
307
- t. transmute_ref( )
336
+ t. transmute_ref:: <$allow_shrink> ( )
308
337
}
309
338
}
310
- } }
339
+ } } ;
311
340
}
312
341
313
342
/// Safely transmutes a mutable reference of one type to a mutable reference of
@@ -353,6 +382,29 @@ macro_rules! transmute_ref {
353
382
/// assert_eq!(size_of_val(src), dst_size);
354
383
/// ```
355
384
///
385
+ /// ## `#![allow(shrink)]`
386
+ ///
387
+ /// If `#![allow(shrink)]` is provided, `transmute_mut!` additionally supports
388
+ /// transmutations that shrink the size of the referent; e.g.:
389
+ ///
390
+ /// ```
391
+ /// # use zerocopy::transmute_mut;
392
+ /// # use core::mem::size_of_val; // Not in the prelude on our MSRV
393
+ /// let src: &mut [[u8; 3]] = &mut [[0, 1, 2], [3, 4, 5], [6, 7, 8]][..];
394
+ /// let dst: &mut [[u8; 2]] = transmute_mut!(#![allow(shrink)] src);
395
+ ///
396
+ ///
397
+ /// let dst_len = dst.len();
398
+ /// let dst_size = size_of_val(dst);
399
+ /// assert_eq!(dst, [[0, 1], [2, 3], [4, 5], [6, 7]]);
400
+ ///
401
+ /// assert_eq!(src.len(), 3);
402
+ /// assert_eq!(dst_len, 4);
403
+ ///
404
+ /// assert_eq!(size_of_val(src), 9);
405
+ /// assert_eq!(dst_size, 8);
406
+ /// ```
407
+ ///
356
408
/// # Errors
357
409
///
358
410
/// Violations of the alignment and size compatibility checks are detected
@@ -441,7 +493,18 @@ macro_rules! transmute_ref {
441
493
/// ```
442
494
#[ macro_export]
443
495
macro_rules! transmute_mut {
444
- ( $e: expr) => { {
496
+ ( #![ allow( shrink) ] $e: expr) => {
497
+ $crate:: __transmute_mut_inner!( true , $e)
498
+ } ;
499
+ ( $e: expr) => {
500
+ $crate:: __transmute_mut_inner!( false , $e)
501
+ } ;
502
+ }
503
+
504
+ #[ doc( hidden) ]
505
+ #[ macro_export]
506
+ macro_rules! __transmute_mut_inner {
507
+ ( $allow_shrink: literal, $e: expr) => { {
445
508
// NOTE: This must be a macro (rather than a function with trait bounds)
446
509
// because, for backwards-compatibility on v0.8.x, we use the autoref
447
510
// specialization trick to dispatch to different `transmute_mut`
@@ -455,7 +518,7 @@ macro_rules! transmute_mut {
455
518
#[ allow( unused) ]
456
519
use $crate:: util:: macro_util:: TransmuteMutDst as _;
457
520
let t = $crate:: util:: macro_util:: Wrap :: new( e) ;
458
- t. transmute_mut( )
521
+ t. transmute_mut:: <$allow_shrink> ( )
459
522
} }
460
523
}
461
524
@@ -1203,6 +1266,11 @@ mod tests {
1203
1266
let slice_of_u16s: & [ U16 ] = <[ U16 ] >:: ref_from_bytes ( & [ 0 , 1 , 2 , 3 , 4 , 5 ] [ ..] ) . unwrap ( ) ;
1204
1267
assert_eq ! ( x, slice_of_u16s) ;
1205
1268
1269
+ // Test that transmuting from a larger sized type to a smaller sized
1270
+ // type works.
1271
+ let x: & u8 = transmute_ref ! ( #![ allow( shrink) ] & 0u16 ) ;
1272
+ assert_eq ! ( * x, 0 ) ;
1273
+
1206
1274
// Test that transmuting from a type with larger trailing slice offset
1207
1275
// and larger trailing slice element works.
1208
1276
let bytes = & [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] [ ..] ;
@@ -1211,6 +1279,15 @@ mod tests {
1211
1279
let x: & SliceDst < U16 , u8 > = transmute_ref ! ( slice_dst_big) ;
1212
1280
assert_eq ! ( x, slice_dst_small) ;
1213
1281
1282
+ let bytes = & [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] [ ..] ;
1283
+ let slice_dst_big = SliceDst :: < [ u8 ; 4 ] , [ u8 ; 4 ] > :: ref_from_bytes ( bytes) . unwrap ( ) ;
1284
+ let slice_dst_small = SliceDst :: < [ u8 ; 3 ] , [ u8 ; 3 ] > :: ref_from_bytes ( & bytes[ ..6 ] ) . unwrap ( ) ;
1285
+ let x: & SliceDst < [ u8 ; 3 ] , [ u8 ; 3 ] > = transmute_ref ! (
1286
+ #![ allow( shrink) ]
1287
+ slice_dst_big
1288
+ ) ;
1289
+ assert_eq ! ( x, slice_dst_small) ;
1290
+
1214
1291
// Test that it's legal to transmute a reference while shrinking the
1215
1292
// lifetime (note that `X` has the lifetime `'static`).
1216
1293
let x: & [ u8 ; 8 ] = transmute_ref ! ( X ) ;
@@ -1391,6 +1468,14 @@ mod tests {
1391
1468
let x: & mut [ i16 ] = transmute_mut ! ( array_of_u16s) ;
1392
1469
assert_eq ! ( x, array_of_i16s) ;
1393
1470
1471
+ // Test that transmuting from a larger sized type to a smaller sized
1472
+ // type works.
1473
+ let mut large: [ u8 ; 2 ] = [ 1 , 1 ] ;
1474
+ let x: & mut u8 = transmute_mut ! ( #![ allow( shrink) ] & mut large) ;
1475
+ assert_eq ! ( * x, 1 ) ;
1476
+ * x = 0 ;
1477
+ assert_eq ! ( large, [ 0 , 1 ] ) ;
1478
+
1394
1479
// Test that transmuting from a type with larger trailing slice offset
1395
1480
// and larger trailing slice element works.
1396
1481
let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
@@ -1399,6 +1484,16 @@ mod tests {
1399
1484
let slice_dst_small = SliceDst :: < U16 , u8 > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
1400
1485
let x: & mut SliceDst < U16 , u8 > = transmute_mut ! ( slice_dst_big) ;
1401
1486
assert_eq ! ( x, slice_dst_small) ;
1487
+
1488
+ let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
1489
+ let slice_dst_big = SliceDst :: < [ u8 ; 4 ] , [ u8 ; 4 ] > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
1490
+ let mut bytes = [ 0 , 1 , 2 , 3 , 4 , 5 ] ;
1491
+ let slice_dst_small = SliceDst :: < [ u8 ; 3 ] , [ u8 ; 3 ] > :: mut_from_bytes ( & mut bytes[ ..] ) . unwrap ( ) ;
1492
+ let x: & mut SliceDst < [ u8 ; 3 ] , [ u8 ; 3 ] > = transmute_mut ! (
1493
+ #![ allow( shrink) ]
1494
+ slice_dst_big
1495
+ ) ;
1496
+ assert_eq ! ( x, slice_dst_small) ;
1402
1497
}
1403
1498
1404
1499
#[ test]
0 commit comments