@@ -1216,7 +1216,7 @@ impl<T> Unalign<T> {
1216
1216
/// Attempts to return a reference to the wrapped `T`, failing if `self` is
1217
1217
/// not properly aligned.
1218
1218
///
1219
- /// If `self` does not satisfy `mem:: align_of::<T>()`, then it is unsound to
1219
+ /// If `self` does not satisfy `align_of::<T>()`, then it is unsound to
1220
1220
/// return a reference to the wrapped `T`, and `try_deref` returns `None`.
1221
1221
///
1222
1222
/// If `T: Unaligned`, then `Unalign<T>` implements [`Deref`], and callers
@@ -1234,7 +1234,7 @@ impl<T> Unalign<T> {
1234
1234
/// Attempts to return a mutable reference to the wrapped `T`, failing if
1235
1235
/// `self` is not properly aligned.
1236
1236
///
1237
- /// If `self` does not satisfy `mem:: align_of::<T>()`, then it is unsound to
1237
+ /// If `self` does not satisfy `align_of::<T>()`, then it is unsound to
1238
1238
/// return a reference to the wrapped `T`, and `try_deref_mut` returns
1239
1239
/// `None`.
1240
1240
///
@@ -1257,7 +1257,7 @@ impl<T> Unalign<T> {
1257
1257
///
1258
1258
/// # Safety
1259
1259
///
1260
- /// If `self` does not satisfy `mem:: align_of::<T>()`, then
1260
+ /// If `self` does not satisfy `align_of::<T>()`, then
1261
1261
/// `self.deref_unchecked()` may cause undefined behavior.
1262
1262
pub const unsafe fn deref_unchecked ( & self ) -> & T {
1263
1263
// SAFETY: `self.get_ptr()` returns a raw pointer to a valid `T` at the
@@ -1276,7 +1276,7 @@ impl<T> Unalign<T> {
1276
1276
///
1277
1277
/// # Safety
1278
1278
///
1279
- /// If `self` does not satisfy `mem:: align_of::<T>()`, then
1279
+ /// If `self` does not satisfy `align_of::<T>()`, then
1280
1280
/// `self.deref_mut_unchecked()` may cause undefined behavior.
1281
1281
pub unsafe fn deref_mut_unchecked ( & mut self ) -> & mut T {
1282
1282
// SAFETY: `self.get_mut_ptr()` returns a raw pointer to a valid `T` at
@@ -1463,6 +1463,177 @@ macro_rules! transmute {
1463
1463
} }
1464
1464
}
1465
1465
1466
+ /// A type whose size is equal to `align_of::<T>()`.
1467
+ #[ doc( hidden) ]
1468
+ #[ allow( missing_debug_implementations) ]
1469
+ #[ repr( C ) ]
1470
+ pub struct AlignOf < T > {
1471
+ // This field ensures that:
1472
+ // - The size is always at least 1 (the minimum possible alignment).
1473
+ // - If the alignment is greater than 1, Rust has to round up to the next
1474
+ // multiple of it in order to make sure that `Align`'s size is a multiple
1475
+ // of that alignment. Without this field, its size could be 0, which is a
1476
+ // valid multiple of any alignment.
1477
+ _u : u8 ,
1478
+ _a : [ T ; 0 ] ,
1479
+ }
1480
+
1481
+ impl < T > AlignOf < T > {
1482
+ #[ doc( hidden) ]
1483
+ pub fn into_t ( self ) -> T {
1484
+ unreachable ! ( )
1485
+ }
1486
+ }
1487
+
1488
+ /// A type whose size is equal to `max(align_of::<T>(), align_of::<U>())`.
1489
+ #[ doc( hidden) ]
1490
+ #[ allow( missing_debug_implementations) ]
1491
+ #[ repr( C ) ]
1492
+ pub union MaxAlignsOf < T , U > {
1493
+ _t : ManuallyDrop < AlignOf < T > > ,
1494
+ _u : ManuallyDrop < AlignOf < U > > ,
1495
+ }
1496
+
1497
+ impl < T , U > MaxAlignsOf < T , U > {
1498
+ #[ doc( hidden) ]
1499
+ pub fn new ( _t : T , _u : U ) -> MaxAlignsOf < T , U > {
1500
+ unreachable ! ( )
1501
+ }
1502
+ }
1503
+
1504
+ /// Safely transmutes a mutable or immutable reference of one type to an
1505
+ /// immutable reference of another type of the same size.
1506
+ ///
1507
+ /// The expression `$e` must have a concrete type, `&T` or `&mut T`, where `T:
1508
+ /// Sized + AsBytes`. The `transmute_ref!` expression must also have a concrete
1509
+ /// type, `&U` (`U` is inferred from the calling context), where `U: Sized +
1510
+ /// FromBytes`. It must be the case that `align_of::<T>() >= align_of::<U>()`.
1511
+ ///
1512
+ /// The lifetime of the input type, `&T` or `&mut T`, must be the same as or
1513
+ /// outlive the lifetime of the output type, `&U`.
1514
+ ///
1515
+ /// # Alignment increase error message
1516
+ ///
1517
+ /// Because of limitations on macros, the error message generated when
1518
+ /// `transmute_ref!` is used to transmute from a type of lower alignment to a
1519
+ /// type of higher alignment is somewhat confusing. For example, the following
1520
+ /// code:
1521
+ ///
1522
+ /// ```rust,compile_fail
1523
+ /// const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
1524
+ /// ```
1525
+ ///
1526
+ /// ...generates the following error:
1527
+ ///
1528
+ /// ```text
1529
+ /// error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
1530
+ /// --> src/lib.rs:1524:34
1531
+ /// |
1532
+ /// 5 | const INCREASE_ALIGNMENT: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
1533
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1534
+ /// |
1535
+ /// = note: source type: `MaxAlignsOf<[u8; 2], u16>` (16 bits)
1536
+ /// = note: target type: `AlignOf<[u8; 2]>` (8 bits)
1537
+ /// = note: this error originates in the macro `zerocopy::transmute_ref` (in Nightly builds, run with -Z macro-backtrace for more info)
1538
+ /// ```
1539
+ ///
1540
+ /// This is saying that `max(align_of::<T>(), align_of::<U>()) !=
1541
+ /// align_of::<T>()`, which is equivalent to `align_of::<T>() <
1542
+ /// align_of::<U>()`.
1543
+ #[ macro_export]
1544
+ macro_rules! transmute_ref {
1545
+ ( $e: expr) => { {
1546
+ // NOTE: This must be a macro (rather than a function with trait bounds)
1547
+ // because there's no way, in a generic context, to enforce that two
1548
+ // types have the same size or alignment.
1549
+
1550
+ // Reborrow so that mutable references are supported too.
1551
+ //
1552
+ // In the rest of the comments, we refer only to `&T` since this
1553
+ // reborrow ensures that `e` is an immutable reference.
1554
+ let e = & * $e;
1555
+
1556
+ #[ allow( unused, clippy:: diverging_sub_expression) ]
1557
+ if false {
1558
+ // This branch, though never taken, ensures that the type of `e` is
1559
+ // `&T` where `T: 't + Sized + AsBytes`, that the type of this macro
1560
+ // expression is `&U` where `U: 'u + Sized + FromBytes`, and that
1561
+ // `'t` outlives `'u`.
1562
+ const fn transmute<' u, ' t: ' u, T : ' t + Sized + $crate:: AsBytes , U : ' u + Sized + $crate:: FromBytes >( _t: & ' t T ) -> & ' u U {
1563
+ unreachable!( )
1564
+ }
1565
+ transmute( e)
1566
+ } else if false {
1567
+ // This branch, though never taken, ensures that `size_of::<T>() ==
1568
+ // size_of::<U>()`.
1569
+
1570
+ // `t` is inferred to have type `T` because it's assigned to `e` (of
1571
+ // type `&T`) as `&t`.
1572
+ let mut t = unreachable!( ) ;
1573
+ e = & t;
1574
+
1575
+ // `u` is inferred to have type `U` because it's used as `&u` as the
1576
+ // value returned from this branch.
1577
+ //
1578
+ // SAFETY: This code is never run.
1579
+ let u = unsafe { $crate:: __real_transmute( t) } ;
1580
+ & u
1581
+ } else if false {
1582
+ // This branch, though never taken, ensures that the alignment of
1583
+ // `T` is greater than or equal to to the alignment of `U`.
1584
+
1585
+ // `t` is inferred to have type `T` because it's assigned to `e` (of
1586
+ // type `&T`) as `&t`.
1587
+ let mut t = unreachable!( ) ;
1588
+ e = & t;
1589
+
1590
+ // `u` is inferred to have type `U` because it's used as `&u` as the
1591
+ // value returned from this branch.
1592
+ let mut u = unreachable!( ) ;
1593
+
1594
+ // `max_aligns` is inferred to have type `MaxAlignsOf<T, U>` because
1595
+ // of the inferred types of `t` and `u`.
1596
+ let max_aligns = $crate:: MaxAlignsOf :: new( t, u) ;
1597
+ // The type wildcard in this bound is inferred to be `T` because
1598
+ // `align_of.into_t()` is assigned to `t` (which has type `T`).
1599
+ //
1600
+ // This transmute will only compile successfully if
1601
+ // `max(align_of::<T>(), align_of::<U>()) == align_of::<T>()` - in
1602
+ // other words, if `align_of::<T>() >= align_of::<U>()`.
1603
+ //
1604
+ // SAFETY: This code is never run.
1605
+ let align_of: $crate:: AlignOf <_> = unsafe { $crate:: __real_transmute( max_aligns) } ;
1606
+ t = align_of. into_t( ) ;
1607
+
1608
+ & u
1609
+ } else {
1610
+ // SAFETY:
1611
+ // - We know that the input and output types are both `Sized` (ie,
1612
+ // thin) references thanks to the trait bounds on `transmute`
1613
+ // above, and thanks to the fact that transmute takes and returns
1614
+ // references.
1615
+ // - We know that it is sound to view the target type of the input
1616
+ // reference (`T`) as the target type of the output reference
1617
+ // (`U`) because `T: AsBytes` and `U: FromBytes` (guaranteed by
1618
+ // trait bounds on `transmute`) and because `size_of::<T>() ==
1619
+ // size_of::<U>()` (guaranteed by the first `__real_transmute`
1620
+ // above).
1621
+ // - We know that alignment is not increased thanks to the second
1622
+ // `__real_transmute` above (the one which transmutes
1623
+ // `MaxAlignsOf` into `AlignOf`).
1624
+ //
1625
+ // We use `$crate::__real_transmute` because we know it will always
1626
+ // be available for crates which are using the 2015 edition of Rust.
1627
+ // By contrast, if we were to use `std::mem::transmute`, this macro
1628
+ // would not work for such crates in `no_std` contexts, and if we
1629
+ // were to use `core::mem::transmute`, this macro would not work in
1630
+ // `std` contexts in which `core` was not manually imported. This is
1631
+ // not a problem for 2018 edition crates.
1632
+ unsafe { $crate:: __real_transmute( e) }
1633
+ }
1634
+ } }
1635
+ }
1636
+
1466
1637
/// A length- and alignment-checked reference to a byte slice which can safely
1467
1638
/// be reinterpreted as another type.
1468
1639
///
@@ -2320,11 +2491,11 @@ impl<T: ?Sized> AsAddress for *mut T {
2320
2491
}
2321
2492
}
2322
2493
2323
- /// Is `t` aligned to `mem:: align_of::<U>()`?
2494
+ /// Is `t` aligned to `align_of::<U>()`?
2324
2495
#[ inline( always) ]
2325
2496
fn aligned_to < T : AsAddress , U > ( t : T ) -> bool {
2326
- // `mem:: align_of::<U>()` is guaranteed to return a non-zero value, which in
2327
- // turn guarantees that this mod operation will not panic.
2497
+ // `align_of::<U>()` is guaranteed to return a non-zero value, which in turn
2498
+ // guarantees that this mod operation will not panic.
2328
2499
#[ allow( clippy:: arithmetic_side_effects) ]
2329
2500
let remainder = t. addr ( ) % mem:: align_of :: < U > ( ) ;
2330
2501
remainder == 0
@@ -3195,6 +3366,90 @@ mod tests {
3195
3366
assert_eq ! ( X , ARRAY_OF_ARRAYS ) ;
3196
3367
}
3197
3368
3369
+ #[ test]
3370
+ fn test_align_of ( ) {
3371
+ macro_rules! test {
3372
+ ( $ty: ty) => {
3373
+ assert_eq!( mem:: size_of:: <AlignOf <$ty>>( ) , mem:: align_of:: <$ty>( ) ) ;
3374
+ } ;
3375
+ }
3376
+
3377
+ test ! ( ( ) ) ;
3378
+ test ! ( u8 ) ;
3379
+ test ! ( AU64 ) ;
3380
+ test ! ( [ AU64 ; 2 ] ) ;
3381
+ }
3382
+
3383
+ #[ test]
3384
+ fn test_max_aligns_of ( ) {
3385
+ macro_rules! test {
3386
+ ( $t: ty, $u: ty) => {
3387
+ assert_eq!(
3388
+ mem:: size_of:: <MaxAlignsOf <$t, $u>>( ) ,
3389
+ core:: cmp:: max( mem:: align_of:: <$t>( ) , mem:: align_of:: <$u>( ) )
3390
+ ) ;
3391
+ } ;
3392
+ }
3393
+
3394
+ test ! ( u8 , u8 ) ;
3395
+ test ! ( u8 , AU64 ) ;
3396
+ test ! ( AU64 , u8 ) ;
3397
+ }
3398
+
3399
+ #[ test]
3400
+ fn test_typed_align_check ( ) {
3401
+ // Test that the type-based alignment check used in `transmute_ref!`
3402
+ // behaves as expected.
3403
+
3404
+ macro_rules! assert_t_align_gteq_u_align {
3405
+ ( $t: ty, $u: ty, $gteq: expr) => {
3406
+ assert_eq!(
3407
+ mem:: size_of:: <MaxAlignsOf <$t, $u>>( ) == mem:: size_of:: <AlignOf <$t>>( ) ,
3408
+ $gteq
3409
+ ) ;
3410
+ } ;
3411
+ }
3412
+
3413
+ assert_t_align_gteq_u_align ! ( u8 , u8 , true ) ;
3414
+ assert_t_align_gteq_u_align ! ( AU64 , AU64 , true ) ;
3415
+ assert_t_align_gteq_u_align ! ( AU64 , u8 , true ) ;
3416
+ assert_t_align_gteq_u_align ! ( u8 , AU64 , false ) ;
3417
+ }
3418
+
3419
+ #[ test]
3420
+ fn test_transmute_ref ( ) {
3421
+ // Test that memory is transmuted as expected.
3422
+ let array_of_u8s = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3423
+ let array_of_arrays = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3424
+ let x: & [ [ u8 ; 2 ] ; 4 ] = transmute_ref ! ( & array_of_u8s) ;
3425
+ assert_eq ! ( * x, array_of_arrays) ;
3426
+ let x: & [ u8 ; 8 ] = transmute_ref ! ( & array_of_arrays) ;
3427
+ assert_eq ! ( * x, array_of_u8s) ;
3428
+
3429
+ // Test that `transmute_ref!` is legal in a const context.
3430
+ const ARRAY_OF_U8S : [ u8 ; 8 ] = [ 0u8 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ;
3431
+ const ARRAY_OF_ARRAYS : [ [ u8 ; 2 ] ; 4 ] = [ [ 0 , 1 ] , [ 2 , 3 ] , [ 4 , 5 ] , [ 6 , 7 ] ] ;
3432
+ #[ allow( clippy:: redundant_static_lifetimes) ]
3433
+ const X : & ' static [ [ u8 ; 2 ] ; 4 ] = transmute_ref ! ( & ARRAY_OF_U8S ) ;
3434
+ assert_eq ! ( * X , ARRAY_OF_ARRAYS ) ;
3435
+
3436
+ // Test that it's legal to transmute a reference while shrinking the
3437
+ // lifetime (note that `X` has the lifetime `'static`).
3438
+ let x: & [ u8 ; 8 ] = transmute_ref ! ( X ) ;
3439
+ assert_eq ! ( * x, ARRAY_OF_U8S ) ;
3440
+
3441
+ // Test that `transmute_ref!` supports decreasing alignment.
3442
+ let u = AU64 ( 0 ) ;
3443
+ let array = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
3444
+ let x: & [ u8 ; 8 ] = transmute_ref ! ( & u) ;
3445
+ assert_eq ! ( * x, array) ;
3446
+
3447
+ // Test that a mutable reference can be turned into an immutable one.
3448
+ let mut x = 0u8 ;
3449
+ let y: & u8 = transmute_ref ! ( & mut x) ;
3450
+ assert_eq ! ( * y, 0 ) ;
3451
+ }
3452
+
3198
3453
#[ test]
3199
3454
fn test_address ( ) {
3200
3455
// Test that the `Deref` and `DerefMut` implementations return a
0 commit comments