Skip to content

Commit

Permalink
Implement traits for atomic types
Browse files Browse the repository at this point in the history
Makes progress on #1009. This commit doesn't implement all traits for
`AtomicPtr<T>`, so there's more work to do.
  • Loading branch information
joshlf committed Mar 7, 2024
1 parent 2f32f0e commit 8a10411
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 16 deletions.
36 changes: 35 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,10 @@ use core::{
ops::{Deref, DerefMut},
ptr::{self, NonNull},
slice,
sync::atomic::{
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16, AtomicU32,
AtomicU8, AtomicUsize,
},
};

use crate::pointer::invariant;
Expand Down Expand Up @@ -1096,7 +1100,9 @@ impl_known_layout!(
u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64,
bool, char,
NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize,
AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
AtomicU8, AtomicUsize
);
#[rustfmt::skip]
impl_known_layout!(
Expand All @@ -1106,6 +1112,7 @@ impl_known_layout!(
T => MaybeUninit<T>,
T: ?Sized => *const T,
T: ?Sized => *mut T,
T => AtomicPtr<T>
);
impl_known_layout!(const N: usize, T => [T; N]);

Expand Down Expand Up @@ -3892,6 +3899,33 @@ safety_comment! {
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => NoCell for opt_extern_c_fn!(...));
}

macro_rules! impl_traits_for_atomics {
($($atomics:ident [$inners:ident]),* $(,)?) => {
$(
impl_for_transparent_wrapper!(TryFromBytes for $atomics [UnsafeCell<$inners>]);
impl_for_transparent_wrapper!(FromZeros for $atomics [UnsafeCell<$inners>]);
impl_for_transparent_wrapper!(FromBytes for $atomics [UnsafeCell<$inners>]);
impl_for_transparent_wrapper!(IntoBytes for $atomics [UnsafeCell<$inners>]);
)*
};
}

#[rustfmt::skip]
impl_traits_for_atomics!(
AtomicBool [bool],
AtomicI16 [i16], AtomicI32 [i32], AtomicI8 [i8], AtomicIsize [isize],
AtomicU16 [u16], AtomicU32 [u32], AtomicU8 [u8], AtomicUsize [usize],
);

safety_comment! {
/// SAFETY:
/// TODO
unsafe_impl!(AtomicBool: Unaligned);
unsafe_impl!(AtomicU8: Unaligned);
unsafe_impl!(AtomicI8: Unaligned);
assert_unaligned!(AtomicBool, AtomicU8, AtomicI8);
}

safety_comment! {
/// SAFETY:
/// Per reference [1]:
Expand Down
60 changes: 45 additions & 15 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,42 @@ macro_rules! impl_for_transparent_wrapper {

impl_for_transparent_wrapper!(
@is_bit_valid
$tyvar: $($(? $optbound +)* $($bound +)*)?
=> $trait for $ty
<$tyvar: $($(? $optbound +)* $($bound +)*)?>
$trait for $ty
);
}
};
(
$(#[$attr:meta])*
for $ty:ty [$inner:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {};
(
$(#[$attr:meta])*
$trait:ident $(, $traits:ident)* for $ty:ty [$inner:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)?
) => {
impl_for_transparent_wrapper!(
$(#[$attr])*
$($traits),* for $ty [$inner] $(; |$candidate $(: MaybeAligned<$ref_repr>)? $(: Maybe<$ptr_repr>)?| $is_bit_valid:expr)?
);

$(#[$attr])*
#[allow(non_local_definitions)]
// SAFETY: TODO
unsafe impl $trait for $ty {
#[allow(dead_code, clippy::missing_inline_in_public_items)]
fn only_derive_is_allowed_to_implement_this_trait() {
use crate::{pointer::invariant::Invariants, util::*};

impl_for_transparent_wrapper!(@is_transparent_wrapper $trait);

fn f<I: Invariants>() {
is_transparent_wrapper::<I, $inner, $ty>();
}
}

impl_for_transparent_wrapper!(@is_bit_valid $trait for $ty);
}
};
(@is_transparent_wrapper NoCell) => {
// SAFETY: `W: TransparentWrapper<UnsafeCellVariance=Covariant>`
// requires that `W` has `UnsafeCell`s at the same byte offsets as
Expand Down Expand Up @@ -299,8 +330,8 @@ macro_rules! impl_for_transparent_wrapper {
};
(
@is_bit_valid
$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?
=> TryFromBytes for $ty:ty
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
TryFromBytes for $ty:ty
) => {
// SAFETY: See safety comment in `(@is_transparent_wrapper
// TryFromBytes)` macro arm for an explanation of why this is a sound
Expand All @@ -312,8 +343,8 @@ macro_rules! impl_for_transparent_wrapper {
};
(
@is_bit_valid
$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?
=> $trait:ident for $ty:ty
$(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)?
$trait:ident for $ty:ty
) => {
// Trait other than `TryFromBytes`; no `is_bit_valid` impl.
};
Expand Down Expand Up @@ -553,15 +584,14 @@ macro_rules! unsafe_impl_known_layout {
/// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
/// unsized types.
macro_rules! assert_unaligned {
($ty:ty) => {
// We only compile this assertion under `cfg(test)` to avoid taking an
// extra non-dev dependency (and making this crate more expensive to
// compile for our dependents).
#[cfg(test)]
static_assertions::const_assert_eq!(core::mem::align_of::<$ty>(), 1);
};
($($ty:ty),*) => {
$(assert_unaligned!($ty);)*
($($tys:ty),*) => {
$(
// We only compile this assertion under `cfg(test)` to avoid taking
// an extra non-dev dependency (and making this crate more expensive
// to compile for our dependents).
#[cfg(test)]
static_assertions::const_assert_eq!(core::mem::align_of::<$tys>(), 1);
)*
};
}

Expand Down

0 comments on commit 8a10411

Please sign in to comment.