use crate::{
index::{
BitIdx,
BitMask,
BitRegister,
},
order::BitOrder,
};
use core::{
fmt::Debug,
sync::atomic::Ordering,
};
use radium::Radium;
pub trait BitAccess: Debug + Radium + Sized
where <Self as Radium>::Item: BitRegister
{
#[inline]
fn clear_bit<O>(&self, index: BitIdx<<Self as Radium>::Item>)
where O: BitOrder {
self.fetch_and(!index.select::<O>().value(), Ordering::Relaxed);
}
#[inline]
fn clear_bits(&self, mask: BitMask<<Self as Radium>::Item>) {
self.fetch_and(!mask.value(), Ordering::Relaxed);
}
#[inline]
fn set_bit<O>(&self, index: BitIdx<<Self as Radium>::Item>)
where O: BitOrder {
self.fetch_or(index.select::<O>().value(), Ordering::Relaxed);
}
#[inline]
fn set_bits(&self, mask: BitMask<<Self as Radium>::Item>) {
self.fetch_or(mask.value(), Ordering::Relaxed);
}
#[inline]
fn invert_bit<O>(&self, index: BitIdx<<Self as Radium>::Item>)
where O: BitOrder {
self.fetch_xor(index.select::<O>().value(), Ordering::Relaxed);
}
#[inline]
fn invert_bits(&self, mask: BitMask<<Self as Radium>::Item>) {
self.fetch_xor(mask.value(), Ordering::Relaxed);
}
#[inline]
fn write_bit<O>(&self, index: BitIdx<<Self as Radium>::Item>, value: bool)
where O: BitOrder {
if value {
self.set_bit::<O>(index);
}
else {
self.clear_bit::<O>(index);
}
}
#[inline]
fn write_bits(&self, mask: BitMask<<Self as Radium>::Item>, value: bool) {
if value {
self.set_bits(mask);
}
else {
self.clear_bits(mask);
}
}
#[inline]
fn get_writer<O>(
value: bool,
) -> for<'a> fn(&'a Self, BitIdx<<Self as Radium>::Item>)
where O: BitOrder {
[Self::clear_bit::<O>, Self::set_bit::<O>][value as usize]
}
#[inline]
fn get_writers(
value: bool,
) -> for<'a> fn(&'a Self, BitMask<<Self as Radium>::Item>) {
[Self::clear_bits, Self::set_bits][value as usize]
}
#[inline]
unsafe fn store_value(&self, value: <Self as Radium>::Item) {
self.store(value, Ordering::Relaxed)
}
}
impl<A> BitAccess for A
where
A: Debug + Radium,
<Self as Radium>::Item: BitRegister,
{
}
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;
#[test]
fn touch_memory() {
let mut data = 0u8;
let bits = data.view_bits_mut::<LocalBits>();
let accessor = unsafe { &*(bits.bitptr().pointer().to_access()) };
BitAccess::set_bit::<Lsb0>(accessor, BitIdx::ZERO);
assert_eq!(accessor.get(), 1);
BitAccess::set_bits(accessor, BitMask::ALL);
assert_eq!(accessor.get(), !0);
BitAccess::clear_bit::<Lsb0>(accessor, BitIdx::ZERO);
assert_eq!(accessor.get(), !1);
BitAccess::clear_bits(accessor, BitMask::ALL);
assert_eq!(accessor.get(), 0);
BitAccess::invert_bit::<Lsb0>(accessor, BitIdx::ZERO);
assert_eq!(accessor.get(), 1);
BitAccess::invert_bits(accessor, BitMask::ALL);
assert_eq!(accessor.get(), !1);
assert!(!BitStore::get_bit::<Lsb0>(accessor, BitIdx::ZERO));
assert_eq!(accessor.get(), !1);
BitAccess::write_bit::<Lsb0>(accessor, BitIdx::new(1).unwrap(), false);
assert_eq!(accessor.get(), !3);
BitAccess::write_bits(accessor, BitMask::ALL, true);
assert_eq!(accessor.get(), !0);
BitAccess::write_bits(accessor, Lsb0::mask(BitIdx::new(2), None), false);
assert_eq!(
BitStore::get_bits(accessor, Lsb0::mask(BitIdx::new(2), None)),
0
);
assert_eq!(accessor.get(), 3);
BitAccess::get_writer::<Lsb0>(false)(accessor, BitIdx::ZERO);
assert_eq!(accessor.get(), 2);
unsafe {
BitAccess::store_value(accessor, !1);
}
assert_eq!(accessor.get(), !1);
}
#[test]
#[cfg(not(miri))]
fn sanity_check_prefetch() {
use core::cell::Cell;
assert_eq!(
<Cell<u8> as BitAccess>::get_writer::<Msb0>(false) as *const (),
<Cell<u8> as BitAccess>::clear_bit::<Msb0> as *const ()
);
assert_eq!(
<Cell<u8> as BitAccess>::get_writer::<Msb0>(true) as *const (),
<Cell<u8> as BitAccess>::set_bit::<Msb0> as *const ()
);
assert_eq!(
<Cell<u8> as BitAccess>::get_writers(false) as *const (),
<Cell<u8> as BitAccess>::clear_bits as *const ()
);
assert_eq!(
<Cell<u8> as BitAccess>::get_writers(true) as *const (),
<Cell<u8> as BitAccess>::set_bits as *const ()
);
}
}