use core::{
cell::Cell,
cmp,
fmt::{
self,
Debug,
Display,
Formatter,
Pointer,
},
hash::{
Hash,
Hasher,
},
marker::PhantomData,
mem,
ops::{
Deref,
DerefMut,
Not,
},
};
use super::{
BitPtr,
Const,
Mut,
Mutability,
};
use crate::{
order::{
BitOrder,
Lsb0,
},
store::BitStore,
};
#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
#[cfg_attr(
not(any(target_pointer_width = "32", target_pointer_width = "64")),
repr(C)
)]
pub struct BitRef<'a, M, O = Lsb0, T = usize>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
bitptr: BitPtr<M, O, T>,
data: bool,
_pad: [u8; PADDING],
_ref: PhantomData<&'a Cell<bool>>,
}
impl<M, O, T> BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline]
pub unsafe fn from_bitptr(bitptr: BitPtr<M, O, T>) -> Self {
let data = bitptr.read();
Self {
bitptr,
data,
_pad: [0; PADDING],
_ref: PhantomData,
}
}
#[inline(always)]
#[cfg(not(tarpaulin_include))]
pub(crate) unsafe fn remove_alias(this: BitRef<M, O, T::Alias>) -> Self {
Self {
bitptr: this.bitptr.cast::<T>(),
data: this.data,
_pad: [0; PADDING],
_ref: PhantomData,
}
}
#[inline(always)]
#[cfg(not(tarpaulin_include))]
pub fn into_bitptr(self) -> BitPtr<M, O, T> {
self.bitptr
}
}
impl<O, T> BitRef<'_, Mut, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline(always)]
#[cfg(not(tarpaulin_include))]
pub fn replace(&mut self, src: bool) -> bool {
mem::replace(&mut self.data, src)
}
#[inline(always)]
#[cfg(not(tarpaulin_include))]
pub fn swap<O2, T2>(&mut self, other: &mut BitRef<Mut, O2, T2>)
where
O2: BitOrder,
T2: BitStore,
{
mem::swap(&mut self.data, &mut other.data)
}
#[inline]
pub fn set(mut self, value: bool) {
self.write(value);
mem::forget(self);
}
#[inline]
fn write(&mut self, value: bool) {
self.data = value;
unsafe {
self.bitptr.write(value);
}
}
}
#[cfg(not(tarpaulin_include))]
impl<O, T> Clone for BitRef<'_, Const, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn clone(&self) -> Self {
Self { ..*self }
}
}
impl<M, O, T> Eq for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> Ord for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.data.cmp(&other.data)
}
}
#[cfg(not(tarpaulin_include))]
impl<M1, M2, O1, O2, T1, T2> PartialEq<BitRef<'_, M2, O2, T2>>
for BitRef<'_, M1, O1, T1>
where
M1: Mutability,
M2: Mutability,
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline(always)]
fn eq(&self, other: &BitRef<'_, M2, O2, T2>) -> bool {
self.data == other.data
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> PartialEq<bool> for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn eq(&self, other: &bool) -> bool {
self.data == *other
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> PartialEq<&bool> for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn eq(&self, other: &&bool) -> bool {
self.data == **other
}
}
#[cfg(not(tarpaulin_include))]
impl<M1, M2, O1, O2, T1, T2> PartialOrd<BitRef<'_, M2, O2, T2>>
for BitRef<'_, M1, O1, T1>
where
M1: Mutability,
M2: Mutability,
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline(always)]
fn partial_cmp(
&self,
other: &BitRef<'_, M2, O2, T2>,
) -> Option<cmp::Ordering> {
self.data.partial_cmp(&other.data)
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> PartialOrd<bool> for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn partial_cmp(&self, other: &bool) -> Option<cmp::Ordering> {
self.data.partial_cmp(other)
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> PartialOrd<&bool> for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn partial_cmp(&self, other: &&bool) -> Option<cmp::Ordering> {
self.data.partial_cmp(*other)
}
}
impl<M, O, T> Debug for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
unsafe { self.bitptr.span_unchecked(1) }
.render(fmt, "Ref", &[("bit", &self.data as &dyn Debug)])
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> Display for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Display::fmt(&self.data, fmt)
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> Pointer for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Pointer::fmt(&self.bitptr, fmt)
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> Hash for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn hash<H>(&self, state: &mut H)
where H: Hasher {
self.bitptr.hash(state);
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> Deref for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
type Target = bool;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.data
}
}
#[cfg(not(tarpaulin_include))]
impl<O, T> DerefMut for BitRef<'_, Mut, O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<M, O, T> Drop for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
fn drop(&mut self) {
if M::CONTAINS_MUTABILITY {
unsafe {
self.bitptr.assert_mut().write(self.data);
}
}
}
}
#[cfg(not(tarpaulin_include))]
impl<M, O, T> Not for BitRef<'_, M, O, T>
where
M: Mutability,
O: BitOrder,
T: BitStore,
{
type Output = bool;
#[inline(always)]
fn not(self) -> Self::Output {
!self.data
}
}
const PADDING: usize = mem::size_of::<*const u8>() + mem::size_of::<usize>()
- mem::size_of::<BitPtr<Const, Lsb0, usize>>()
- mem::size_of::<bool>();
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn proxy_ref() {
let bits = bits![mut 0; 2];
assert!(bits.not_any());
let mut proxy = bits.first_mut().unwrap();
*proxy = true;
assert!(*proxy);
drop(proxy);
assert!(bits[0]);
let proxy = bits.get_mut(1).unwrap();
proxy.set(true);
assert!(bits[1]);
}
#[test]
#[cfg(feature = "alloc")]
fn format() {
#[cfg(not(feature = "std"))]
use alloc::format;
use crate::order::Msb0;
let bits = bits![mut Msb0, u8; 0];
let mut bit = bits.get_mut(0).unwrap();
let text = format!("{:?}", bit);
assert!(text.starts_with("BitRef<bitvec::order::Msb0, u8> { addr: 0x"));
assert!(text.ends_with(", head: 000, bits: 1, bit: false }"));
*bit = true;
let text = format!("{:?}", bit);
assert!(text.starts_with("BitRef<bitvec::order::Msb0, u8> { addr: 0x"));
assert!(text.ends_with(", head: 000, bits: 1, bit: true }"));
}
#[test]
fn assert_size() {
assert_eq!(
mem::size_of::<BitRef<'static, Const, Lsb0, u8>>(),
2 * mem::size_of::<usize>(),
);
assert_eq!(
mem::align_of::<BitRef<'static, Const, Lsb0, u8>>(),
mem::align_of::<*const u8>(),
);
}
}