This commit is contained in:
Emil Fresk 2024-02-15 16:14:03 +01:00
parent a76f650c46
commit 7b2b7c64cc

View file

@ -2,11 +2,9 @@
use bitflags::{Bits, Flags}; use bitflags::{Bits, Flags};
use core::sync::atomic::{AtomicU16, AtomicU8, Ordering}; use core::sync::atomic::{AtomicU16, AtomicU8, Ordering};
use portable_atomic::{AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU32, AtomicU64};
// /// A channel for setting and clearing `bitflags` concurrently.
// Bit channel
//
pub struct BitChannel<T: Flags> pub struct BitChannel<T: Flags>
where where
T: Flags, T: Flags,
@ -20,44 +18,73 @@ where
T: Flags, T: Flags,
T::Bits: AtomicType, T::Bits: AtomicType,
{ {
/// Create a new `bitflags` channel.
pub const fn new() -> Self { pub const fn new() -> Self {
BitChannel { BitChannel {
atomic: T::Bits::ATOMIC_ZERO, atomic: T::Bits::ATOMIC_ZERO,
} }
} }
pub fn test(&self) { /// Set `bitflag`s.
T::Bits::fetch_and(&self.atomic, T::Bits::EMPTY, Ordering::Relaxed); #[inline]
pub fn send(&self, flags: T) {
T::Bits::fetch_or(&self.atomic, flags.bits(), Ordering::Relaxed);
}
/// Receive the current value of the `bitflags` and reset all flags.
#[inline]
pub fn recv(&self) -> T {
<T as Flags>::from_bits_retain(T::Bits::fetch_and(
&self.atomic,
T::Bits::EMPTY,
Ordering::Relaxed,
))
} }
} }
/// Generic atomic trait, allows for taking any `bitflags::Bits` as an atomic.
pub trait AtomicType: Sized { pub trait AtomicType: Sized {
/// The underlying atomic, e.g. `AtomicU8`, `AtomicU16`.
type Atomic: From<Self>; type Atomic: From<Self>;
/// The definition of that atomic with value 0.
const ATOMIC_ZERO: Self::Atomic; const ATOMIC_ZERO: Self::Atomic;
/// The atomic's `fetch_and` implementation forwarded.
fn fetch_and(a: &Self::Atomic, b: Self, order: Ordering) -> Self; fn fetch_and(a: &Self::Atomic, b: Self, order: Ordering) -> Self;
/// The atomic's `fetch_or` implementation forwarded.
fn fetch_or(a: &Self::Atomic, b: Self, order: Ordering) -> Self;
} }
impl AtomicType for u16 { macro_rules! atomic_type_impl {
type Atomic = AtomicU16; ($atomic:ty, $integer:ty) => {
impl AtomicType for $integer {
const ATOMIC_ZERO: Self::Atomic = AtomicU16::new(0); type Atomic = $atomic;
fn fetch_and(a: &Self::Atomic, b: Self, order: Ordering) -> Self { const ATOMIC_ZERO: Self::Atomic = <$atomic>::new(0);
a.fetch_and(b, order)
} #[inline(always)]
fn fetch_and(a: &Self::Atomic, b: Self, order: Ordering) -> Self {
a.fetch_and(b, order)
}
#[inline(always)]
fn fetch_or(a: &Self::Atomic, b: Self, order: Ordering) -> Self {
a.fetch_or(b, order)
}
}
};
} }
impl AtomicType for u8 { atomic_type_impl!(AtomicU8, u8);
type Atomic = AtomicU8; atomic_type_impl!(AtomicU16, u16);
atomic_type_impl!(AtomicU32, u32);
const ATOMIC_ZERO: Self::Atomic = AtomicU8::new(0); atomic_type_impl!(AtomicU64, u64);
atomic_type_impl!(AtomicI8, i8);
fn fetch_and(a: &Self::Atomic, b: Self, order: Ordering) -> Self { atomic_type_impl!(AtomicI16, i16);
a.fetch_and(b, order) atomic_type_impl!(AtomicI32, i32);
} atomic_type_impl!(AtomicI64, i64);
}
// etc... // etc...
@ -86,4 +113,3 @@ mod tests {
let b = BitChannel::<FlagsU16>::new(); let b = BitChannel::<FlagsU16>::new();
} }
} }