use crate::{
domain::Domain,
mem::BitMemory,
order::BitOrder,
slice::BitSlice,
store::BitStore,
view::BitView,
};
use core::{
any,
cmp,
convert::TryFrom,
fmt::{
self,
Binary,
Debug,
Display,
Formatter,
LowerHex,
Octal,
Pointer,
UpperHex,
},
hash::{
Hash,
Hasher,
},
str,
};
use tap::pipe::Pipe;
#[cfg(feature = "alloc")]
use crate::vec::BitVec;
#[cfg(feature = "alloc")]
use alloc::borrow::ToOwned;
impl<O, T> Eq for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
}
impl<O, T> Ord for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn cmp(&self, rhs: &Self) -> cmp::Ordering {
self.partial_cmp(rhs)
.expect("BitSlice has a total ordering")
}
}
impl<O1, O2, T1, T2> PartialEq<BitSlice<O2, T2>> for BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
fn eq(&self, rhs: &BitSlice<O2, T2>) -> bool {
self.len() == rhs.len()
&& self.iter().zip(rhs.iter()).all(|(l, r)| l == r)
}
}
#[cfg(not(tarpaulin_include))]
impl<O1, O2, T1, T2> PartialEq<BitSlice<O2, T2>> for &BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn eq(&self, rhs: &BitSlice<O2, T2>) -> bool {
**self == rhs
}
}
#[cfg(not(tarpaulin_include))]
impl<O1, O2, T1, T2> PartialEq<BitSlice<O2, T2>> for &mut BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn eq(&self, rhs: &BitSlice<O2, T2>) -> bool {
**self == rhs
}
}
#[cfg(not(tarpaulin_include))]
impl<O1, O2, T1, T2> PartialEq<&BitSlice<O2, T2>> for BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn eq(&self, rhs: &&BitSlice<O2, T2>) -> bool {
*self == **rhs
}
}
#[cfg(not(tarpaulin_include))]
impl<O1, O2, T1, T2> PartialEq<&mut BitSlice<O2, T2>> for BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn eq(&self, rhs: &&mut BitSlice<O2, T2>) -> bool {
*self == **rhs
}
}
impl<O1, O2, T1, T2> PartialOrd<BitSlice<O2, T2>> for BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
fn partial_cmp(&self, rhs: &BitSlice<O2, T2>) -> Option<cmp::Ordering> {
for (l, r) in self.iter().zip(rhs.iter()) {
match (l, r) {
(true, false) => return Some(cmp::Ordering::Greater),
(false, true) => return Some(cmp::Ordering::Less),
_ => continue,
}
}
self.len().partial_cmp(&rhs.len())
}
}
impl<O1, O2, T1, T2> PartialOrd<BitSlice<O2, T2>> for &BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn partial_cmp(&self, rhs: &BitSlice<O2, T2>) -> Option<cmp::Ordering> {
(*self).partial_cmp(rhs)
}
}
impl<O1, O2, T1, T2> PartialOrd<BitSlice<O2, T2>> for &mut BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn partial_cmp(&self, rhs: &BitSlice<O2, T2>) -> Option<cmp::Ordering> {
(**self).partial_cmp(rhs)
}
}
impl<O1, O2, T1, T2> PartialOrd<&BitSlice<O2, T2>> for BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn partial_cmp(&self, rhs: &&BitSlice<O2, T2>) -> Option<cmp::Ordering> {
(*self).partial_cmp(&**rhs)
}
}
impl<O1, O2, T1, T2> PartialOrd<&mut BitSlice<O2, T2>> for BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn partial_cmp(&self, rhs: &&mut BitSlice<O2, T2>) -> Option<cmp::Ordering> {
(*self).partial_cmp(&**rhs)
}
}
impl<O1, O2, T1, T2> PartialOrd<&mut BitSlice<O2, T2>> for &BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn partial_cmp(&self, rhs: &&mut BitSlice<O2, T2>) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs)
}
}
impl<O1, O2, T1, T2> PartialOrd<&BitSlice<O2, T2>> for &mut BitSlice<O1, T1>
where
O1: BitOrder,
O2: BitOrder,
T1: BitStore,
T2: BitStore,
{
#[inline]
fn partial_cmp(&self, rhs: &&BitSlice<O2, T2>) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs)
}
}
#[cfg(not(tarpaulin_include))]
impl<'a, O, T> TryFrom<&'a [T]> for &'a BitSlice<O, T>
where
O: BitOrder,
T: BitStore + BitMemory,
{
type Error = &'a [T];
#[inline]
fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
BitSlice::from_slice(slice).ok_or(slice)
}
}
impl<O, T> Default for &BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn default() -> Self {
BitSlice::empty()
}
}
impl<O, T> Default for &mut BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn default() -> Self {
BitSlice::empty_mut()
}
}
#[cfg(not(tarpaulin_include))]
impl<O, T> Debug for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
if fmt.alternate() {
Pointer::fmt(self, fmt)?;
fmt.write_str(" ")?;
}
Binary::fmt(self, fmt)
}
}
#[cfg(not(tarpaulin_include))]
impl<O, T> Display for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline(always)]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
Binary::fmt(self, fmt)
}
}
#[cfg(not(tarpaulin_include))]
impl<O, T> Pointer for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
self.bitptr()
.render(fmt, "Slice", Some(any::type_name::<O>()), None)
}
}
macro_rules! fmt {
($trait:ident, $base:expr, $pfx:expr, $blksz:expr) => {
impl<O, T> $trait for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
struct Seq<'a>(&'a [u8]);
impl Debug for Seq<'_> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str(unsafe {
str::from_utf8_unchecked(self.0)
})
}
}
let start = if fmt.alternate() { 0 } else { 2 };
let mut dbg = fmt.debug_list();
let mut w: [u8; (usize::BITS as usize / $blksz) + 2] =
[b'0'; (usize::BITS as usize / $blksz) + 2];
w[1] = $pfx;
let mut writer = |bits: &BitSlice<O, T::Mem>| {
let mut end = 2;
for (index, chunk) in bits.rchunks($blksz).rev().enumerate()
{
let mut val = 0u8;
for bit in chunk {
val <<= 1;
val |= *bit as u8;
}
w[2 + index] = match val {
v @ 0 ..= 9 => b'0' + v,
v @ 10 ..= 16 => $base + (v - 10),
_ => unsafe { core::hint::unreachable_unchecked() },
};
end += 1;
}
dbg.entry(&Seq(&w[start .. end]));
};
match self.domain() {
Domain::Enclave { head, elem, tail } => {
let tmp = elem.load_value();
let bits = tmp.view_bits::<O>();
unsafe {
bits.get_unchecked(
head.value() as usize .. tail.value() as usize,
)
}
.pipe(writer);
},
Domain::Region { head, body, tail } => {
if let Some((head, elem)) = head {
let tmp = elem.load_value();
let bits = tmp.view_bits::<O>();
unsafe {
bits.get_unchecked(head.value() as usize ..)
}
.pipe(&mut writer);
}
for elem in body.iter() {
elem.pipe(BitSlice::<O, T::Mem>::from_element)
.pipe(&mut writer);
}
if let Some((elem, tail)) = tail {
let tmp = elem.load_value();
let bits = tmp.view_bits::<O>();
unsafe {
bits.get_unchecked(.. tail.value() as usize)
}
.pipe(&mut writer);
}
},
}
dbg.finish()
}
}
};
}
fmt!(Binary, b'0', b'b', 1);
fmt!(Octal, b'0', b'o', 3);
fmt!(LowerHex, b'a', b'x', 4);
fmt!(UpperHex, b'A', b'x', 4);
#[cfg(not(tarpaulin_include))]
impl<O, T> Hash for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn hash<H>(&self, hasher: &mut H)
where H: Hasher {
for bit in self {
hasher.write_u8(*bit as u8);
}
}
}
unsafe impl<O, T> Send for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
T::Threadsafe: Send,
{
}
unsafe impl<O, T> Sync for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
T::Threadsafe: Sync,
{
}
#[cfg(feature = "alloc")]
impl<O, T> ToOwned for BitSlice<O, T>
where
O: BitOrder,
T: BitStore,
{
type Owned = BitVec<O, T>;
#[inline]
fn to_owned(&self) -> Self::Owned {
BitVec::from_bitslice(self)
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[test]
fn cmp() {
let data = 0x45u8;
let bits = data.view_bits::<Msb0>();
let a = &bits[.. 3];
let b = &bits[.. 4];
let c = &bits[.. 5];
let d = &bits[4 ..];
assert!(a < b);
assert!(b < c);
assert!(c < d);
}
}
#[cfg(all(test, feature = "alloc"))]
mod format {
use crate::prelude::*;
#[cfg(not(feature = "std"))]
use alloc::format;
#[test]
fn binary() {
let data = [0u8, 0x0F, !0];
let bits = data.view_bits::<Msb0>();
assert_eq!(format!("{:b}", &bits[.. 0]), "[]");
assert_eq!(format!("{:#b}", &bits[.. 0]), "[]");
assert_eq!(format!("{:b}", &bits[9 .. 15]), "[000111]");
assert_eq!(
format!("{:#b}", &bits[9 .. 15]),
"[
0b000111,
]"
);
assert_eq!(format!("{:b}", &bits[4 .. 20]), "[0000, 00001111, 1111]");
assert_eq!(
format!("{:#b}", &bits[4 .. 20]),
"[
0b0000,
0b00001111,
0b1111,
]"
);
assert_eq!(format!("{:b}", &bits[4 ..]), "[0000, 00001111, 11111111]");
assert_eq!(
format!("{:#b}", &bits[4 ..]),
"[
0b0000,
0b00001111,
0b11111111,
]"
);
assert_eq!(format!("{:b}", &bits[.. 20]), "[00000000, 00001111, 1111]");
assert_eq!(
format!("{:#b}", &bits[.. 20]),
"[
0b00000000,
0b00001111,
0b1111,
]"
);
assert_eq!(format!("{:b}", bits), "[00000000, 00001111, 11111111]");
assert_eq!(
format!("{:#b}", bits),
"[
0b00000000,
0b00001111,
0b11111111,
]"
);
}
#[test]
fn octal() {
let data = [0u8, 0x0F, !0];
let bits = data.view_bits::<Msb0>();
assert_eq!(format!("{:o}", &bits[.. 0]), "[]");
assert_eq!(format!("{:#o}", &bits[.. 0]), "[]");
assert_eq!(format!("{:o}", &bits[9 .. 15]), "[07]");
assert_eq!(
format!("{:#o}", &bits[9 .. 15]),
"[
0o07,
]"
);
assert_eq!(format!("{:o}", &bits[4 .. 20]), "[00, 017, 17]");
assert_eq!(
format!("{:#o}", &bits[4 .. 20]),
"[
0o00,
0o017,
0o17,
]"
);
assert_eq!(format!("{:o}", &bits[4 ..]), "[00, 017, 377]");
assert_eq!(
format!("{:#o}", &bits[4 ..]),
"[
0o00,
0o017,
0o377,
]"
);
assert_eq!(format!("{:o}", &bits[.. 20]), "[000, 017, 17]");
assert_eq!(
format!("{:#o}", &bits[.. 20]),
"[
0o000,
0o017,
0o17,
]"
);
assert_eq!(format!("{:o}", bits), "[000, 017, 377]");
assert_eq!(
format!("{:#o}", bits),
"[
0o000,
0o017,
0o377,
]"
);
}
#[test]
fn hex_lower() {
let data = [0u8, 0x0F, !0];
let bits = data.view_bits::<Msb0>();
assert_eq!(format!("{:x}", &bits[.. 0]), "[]");
assert_eq!(format!("{:#x}", &bits[.. 0]), "[]");
assert_eq!(format!("{:x}", &bits[9 .. 15]), "[07]");
assert_eq!(
format!("{:#x}", &bits[9 .. 15]),
"[
0x07,
]"
);
assert_eq!(format!("{:x}", &bits[4 .. 20]), "[0, 0f, f]");
assert_eq!(
format!("{:#x}", &bits[4 .. 20]),
"[
0x0,
0x0f,
0xf,
]"
);
assert_eq!(format!("{:x}", &bits[4 ..]), "[0, 0f, ff]");
assert_eq!(
format!("{:#x}", &bits[4 ..]),
"[
0x0,
0x0f,
0xff,
]"
);
assert_eq!(format!("{:x}", &bits[.. 20]), "[00, 0f, f]");
assert_eq!(
format!("{:#x}", &bits[.. 20]),
"[
0x00,
0x0f,
0xf,
]"
);
assert_eq!(format!("{:x}", bits), "[00, 0f, ff]");
assert_eq!(
format!("{:#x}", bits),
"[
0x00,
0x0f,
0xff,
]"
);
}
#[test]
fn hex_upper() {
let data = [0u8, 0x0F, !0];
let bits = data.view_bits::<Msb0>();
assert_eq!(format!("{:X}", &bits[.. 0]), "[]");
assert_eq!(format!("{:#X}", &bits[.. 0]), "[]");
assert_eq!(format!("{:X}", &bits[9 .. 15]), "[07]");
assert_eq!(
format!("{:#X}", &bits[9 .. 15]),
"[
0x07,
]"
);
assert_eq!(format!("{:X}", &bits[4 .. 20]), "[0, 0F, F]");
assert_eq!(
format!("{:#X}", &bits[4 .. 20]),
"[
0x0,
0x0F,
0xF,
]"
);
assert_eq!(format!("{:X}", &bits[4 ..]), "[0, 0F, FF]");
assert_eq!(
format!("{:#X}", &bits[4 ..]),
"[
0x0,
0x0F,
0xFF,
]"
);
assert_eq!(format!("{:X}", &bits[.. 20]), "[00, 0F, F]");
assert_eq!(
format!("{:#X}", &bits[.. 20]),
"[
0x00,
0x0F,
0xF,
]"
);
assert_eq!(format!("{:X}", bits), "[00, 0F, FF]");
assert_eq!(
format!("{:#X}", bits),
"[
0x00,
0x0F,
0xFF,
]"
);
}
}