use crate::{
access::BitAccess,
index::BitIdx,
order::BitOrder,
slice::BitSlice,
store::BitStore,
};
use core::{
fmt::{
self,
Debug,
Formatter,
},
marker::PhantomData,
mem,
ops::{
Deref,
DerefMut,
},
ptr::NonNull,
};
use wyz::fmt::FmtForward;
pub struct BitMut<'a, O, T>
where
O: BitOrder,
T: 'a + BitStore,
{
addr: NonNull<T::Access>,
head: BitIdx<T::Mem>,
data: bool,
_ref: PhantomData<&'a mut BitSlice<O, T>>,
}
impl<O, T> BitMut<'_, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
pub(crate) unsafe fn new_unchecked(
addr: *const T::Access,
head: BitIdx<T::Mem>,
) -> Self {
Self {
_ref: PhantomData,
addr: NonNull::new_unchecked(addr as *mut T::Access),
head,
data: (&*(addr as *const T)).get_bit::<O>(head),
}
}
#[inline]
pub fn set(mut self, value: bool) {
self.write(value);
mem::forget(self);
}
#[inline]
fn write(&mut self, value: bool) {
unsafe { (&*self.addr.as_ptr()).write_bit::<O>(self.head, value) }
}
}
impl<O, T> Debug for BitMut<'_, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "BitMut<{}>", core::any::type_name::<T::Mem>())?;
fmt.debug_struct("")
.field("addr", &self.addr.as_ptr().fmt_pointer())
.field("head", &self.head.fmt_binary())
.field("data", &self.data)
.finish()
}
}
impl<O, T> Deref for BitMut<'_, O, T>
where
O: BitOrder,
T: BitStore,
{
type Target = bool;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<O, T> DerefMut for BitMut<'_, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<O, T> Drop for BitMut<'_, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn drop(&mut self) {
let value = self.data;
self.write(value);
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn proxy_ref() {
let mut data = 0u32;
let bits = BitSlice::<Lsb0, _>::from_element_mut(&mut data);
assert!(!bits[0]);
let mut proxy = bits.first_mut().unwrap();
*proxy = true;
assert!(*proxy);
drop(proxy);
assert!(bits[0]);
assert_eq!(data, 1);
}
}