#![doc = include_str!("../doc/domain.md")]
use core::{
any,
convert::{
TryFrom,
TryInto,
},
fmt::{
self,
Binary,
Debug,
Display,
Formatter,
LowerHex,
Octal,
UpperHex,
},
hash::{
Hash,
Hasher,
},
iter::FusedIterator,
marker::PhantomData,
};
use tap::{
Conv,
Pipe,
Tap,
};
use wyz::{
comu::{
Address,
Const,
Mut,
Mutability,
Reference,
Referential,
SliceReferential,
},
fmt::FmtForward,
};
use crate::{
access::BitAccess,
index::{
BitEnd,
BitIdx,
BitMask,
},
order::{
BitOrder,
Lsb0,
},
ptr::BitSpan,
slice::BitSlice,
store::BitStore,
};
#[doc = include_str!("../doc/domain/BitDomain.md")]
pub enum BitDomain<'a, M = Const, T = usize, O = Lsb0>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, BitSlice<T, O>>: Referential<'a>,
Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
{
Enclave(Reference<'a, M, BitSlice<T, O>>),
Region {
head: Reference<'a, M, BitSlice<T, O>>,
body: Reference<'a, M, BitSlice<T::Unalias, O>>,
tail: Reference<'a, M, BitSlice<T, O>>,
},
}
impl<'a, M, T, O> BitDomain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, BitSlice<T, O>>: Referential<'a>,
Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
{
#[inline]
pub fn enclave(self) -> Option<Reference<'a, M, BitSlice<T, O>>> {
match self {
Self::Enclave(bits) => Some(bits),
_ => None,
}
}
#[inline]
pub fn region(
self,
) -> Option<(
Reference<'a, M, BitSlice<T, O>>,
Reference<'a, M, BitSlice<T::Unalias, O>>,
Reference<'a, M, BitSlice<T, O>>,
)> {
match self {
Self::Region { head, body, tail } => Some((head, body, tail)),
_ => None,
}
}
}
impl<'a, M, T, O> Default for BitDomain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, BitSlice<T, O>>: Referential<'a>,
Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
Reference<'a, M, BitSlice<T, O>>: Default,
Reference<'a, M, BitSlice<T::Unalias, O>>: Default,
{
#[inline]
fn default() -> Self {
Self::Region {
head: Default::default(),
body: Default::default(),
tail: Default::default(),
}
}
}
impl<'a, M, T, O> Debug for BitDomain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, BitSlice<T, O>>: Referential<'a>,
Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
Reference<'a, M, BitSlice<T, O>>: Debug,
Reference<'a, M, BitSlice<T::Unalias, O>>: Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(
fmt,
"BitDomain::<{} {}, {}>::",
M::RENDER,
any::type_name::<T::Mem>(),
any::type_name::<O>(),
)?;
match self {
Self::Enclave(elem) => {
fmt.debug_tuple("Enclave").field(elem).finish()
},
Self::Region { head, body, tail } => fmt
.debug_struct("Region")
.field("head", head)
.field("body", body)
.field("tail", tail)
.finish(),
}
}
}
#[cfg(not(tarpaulin_include))]
impl<T, O> Clone for BitDomain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T, O> Copy for BitDomain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
}
#[doc = include_str!("../doc/domain/Domain.md")]
pub enum Domain<'a, M = Const, T = usize, O = Lsb0>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, T>: Referential<'a>,
Address<M, [T::Unalias]>: SliceReferential<'a>,
{
Enclave(PartialElement<'a, M, T, O>),
Region {
head: Option<PartialElement<'a, M, T, O>>,
body: Reference<'a, M, [T::Unalias]>,
tail: Option<PartialElement<'a, M, T, O>>,
},
}
impl<'a, M, T, O> Domain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, T>: Referential<'a>,
Address<M, [T::Unalias]>: SliceReferential<'a>,
{
#[inline]
pub fn enclave(self) -> Option<PartialElement<'a, M, T, O>> {
match self {
Self::Enclave(elem) => Some(elem),
_ => None,
}
}
#[inline]
pub fn region(
self,
) -> Option<(
Option<PartialElement<'a, M, T, O>>,
Reference<'a, M, [T::Unalias]>,
Option<PartialElement<'a, M, T, O>>,
)> {
match self {
Self::Region { head, body, tail } => Some((head, body, tail)),
_ => None,
}
}
#[inline]
pub fn into_bit_domain(self) -> BitDomain<'a, M, T, O>
where
Address<M, BitSlice<T, O>>: Referential<'a>,
Address<M, BitSlice<T::Unalias, O>>: Referential<'a>,
Reference<'a, M, BitSlice<T, O>>: Default,
Reference<'a, M, BitSlice<T::Unalias, O>>:
TryFrom<Reference<'a, M, [T::Unalias]>>,
{
match self {
Self::Enclave(elem) => BitDomain::Enclave(elem.into_bitslice()),
Self::Region { head, body, tail } => BitDomain::Region {
head: head.map_or_else(
Default::default,
PartialElement::into_bitslice,
),
body: body.try_into().unwrap_or_else(|_| {
match option_env!("CARGO_PKG_REPOSITORY") {
Some(env) => unreachable!(
"Construction of a slice with length {} should not \
be possible. If this assumption is outdated, \
please file an issue at {}",
(isize::MIN as usize) >> 3,
env,
),
None => unreachable!(
"Construction of a slice with length {} should not \
be possible. If this assumption is outdated, \
please consider filing an issue",
(isize::MIN as usize) >> 3
),
}
}),
tail: tail.map_or_else(
Default::default,
PartialElement::into_bitslice,
),
},
}
}
}
impl<'a, M, T, O> Domain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, T>: Referential<'a>,
Address<M, [T::Unalias]>:
SliceReferential<'a, ElementAddr = Address<M, T::Unalias>>,
Address<M, BitSlice<T, O>>: Referential<'a>,
Reference<'a, M, [T::Unalias]>: Default,
{
pub(crate) fn new(bits: Reference<'a, M, BitSlice<T, O>>) -> Self
where BitSpan<M, T, O>: From<Reference<'a, M, BitSlice<T, O>>> {
let bitspan = bits.conv::<BitSpan<M, T, O>>();
let (head, elts, tail) =
(bitspan.head(), bitspan.elements(), bitspan.tail());
let base = bitspan.address();
let (min, max) = (BitIdx::<T::Mem>::MIN, BitEnd::<T::Mem>::MAX);
let ctor = match (head, elts, tail) {
(_, 0, _) => Self::empty,
(h, _, t) if h == min && t == max => Self::spanning,
(_, _, t) if t == max => Self::partial_head,
(h, ..) if h == min => Self::partial_tail,
(_, 1, _) => Self::minor,
_ => Self::major,
};
ctor(base, elts, head, tail)
}
#[inline]
fn empty(
_: Address<M, T>,
_: usize,
_: BitIdx<T::Mem>,
_: BitEnd<T::Mem>,
) -> Self {
Default::default()
}
#[inline]
fn major(
addr: Address<M, T>,
elts: usize,
head: BitIdx<T::Mem>,
tail: BitEnd<T::Mem>,
) -> Self {
let h_elem = addr;
let t_elem = unsafe { addr.add(elts - 1) };
let body = unsafe {
Address::<M, [T::Unalias]>::from_raw_parts(
addr.add(1).cast::<T::Unalias>(),
elts - 2,
)
};
Self::Region {
head: Some(PartialElement::new(h_elem, head, None)),
body,
tail: Some(PartialElement::new(t_elem, None, tail)),
}
}
#[inline]
fn minor(
addr: Address<M, T>,
_: usize,
head: BitIdx<T::Mem>,
tail: BitEnd<T::Mem>,
) -> Self {
let elem = addr;
Self::Enclave(PartialElement::new(elem, head, tail))
}
#[inline]
fn partial_head(
addr: Address<M, T>,
elts: usize,
head: BitIdx<T::Mem>,
_: BitEnd<T::Mem>,
) -> Self {
let elem = addr;
let body = unsafe {
Address::<M, [T::Unalias]>::from_raw_parts(
addr.add(1).cast::<T::Unalias>(),
elts - 1,
)
};
Self::Region {
head: Some(PartialElement::new(elem, head, None)),
body,
tail: None,
}
}
#[inline]
fn partial_tail(
addr: Address<M, T>,
elts: usize,
_: BitIdx<T::Mem>,
tail: BitEnd<T::Mem>,
) -> Self {
let elem = unsafe { addr.add(elts - 1) };
let body = unsafe {
Address::<M, [T::Unalias]>::from_raw_parts(
addr.cast::<T::Unalias>(),
elts - 1,
)
};
Self::Region {
head: None,
body,
tail: Some(PartialElement::new(elem, None, tail)),
}
}
#[inline]
fn spanning(
addr: Address<M, T>,
elts: usize,
_: BitIdx<T::Mem>,
_: BitEnd<T::Mem>,
) -> Self {
Self::Region {
head: None,
body: unsafe {
<Address<M, [T::Unalias]> as SliceReferential>::from_raw_parts(
addr.cast::<T::Unalias>(),
elts,
)
},
tail: None,
}
}
}
impl<'a, M, T, O> Default for Domain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, T>: Referential<'a>,
Address<M, [T::Unalias]>: SliceReferential<'a>,
Reference<'a, M, [T::Unalias]>: Default,
{
#[inline]
fn default() -> Self {
Self::Region {
head: None,
body: Reference::<M, [T::Unalias]>::default(),
tail: None,
}
}
}
impl<'a, M, T, O> Debug for Domain<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
Address<M, T>: Referential<'a>,
Address<M, [T::Unalias]>: SliceReferential<'a>,
Reference<'a, M, [T::Unalias]>: Debug,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(
fmt,
"Domain::<{} {}, {}>::",
M::RENDER,
any::type_name::<T>(),
any::type_name::<O>(),
)?;
match self {
Self::Enclave(elem) => {
fmt.debug_tuple("Enclave").field(elem).finish()
},
Self::Region { head, body, tail } => fmt
.debug_struct("Region")
.field("head", head)
.field("body", body)
.field("tail", tail)
.finish(),
}
}
}
#[cfg(not(tarpaulin_include))]
impl<T, O> Clone for Domain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T, O> Iterator for Domain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
type Item = T::Mem;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Enclave(elem) => {
elem.load_value().tap(|_| *self = Default::default()).into()
},
Self::Region { head, body, tail } => {
if let Some(elem) = head.take() {
return elem.load_value().into();
}
if let Some((elem, rest)) = body.split_first() {
*body = rest;
return elem.load_value().into();
}
if let Some(elem) = tail.take() {
return elem.load_value().into();
}
None
},
}
}
}
impl<T, O> DoubleEndedIterator for Domain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match self {
Self::Enclave(elem) => {
elem.load_value().tap(|_| *self = Default::default()).into()
},
Self::Region { head, body, tail } => {
if let Some(elem) = tail.take() {
return elem.load_value().into();
}
if let Some((elem, rest)) = body.split_last() {
*body = rest;
return elem.load_value().into();
}
if let Some(elem) = head.take() {
return elem.load_value().into();
}
None
},
}
}
}
impl<T, O> ExactSizeIterator for Domain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
#[inline]
fn len(&self) -> usize {
match self {
Self::Enclave(_) => 1,
Self::Region { head, body, tail } => {
head.is_some() as usize + body.len() + tail.is_some() as usize
},
}
}
}
impl<T, O> FusedIterator for Domain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
}
impl<T, O> Copy for Domain<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
}
macro_rules! fmt {
($($fmt:ty => $fwd:ident),+ $(,)?) => { $(
impl<'a, T, O> $fmt for Domain<'a, Const, T, O>
where
O: BitOrder,
T: BitStore,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.debug_list()
.entries(self.into_iter().map(FmtForward::$fwd))
.finish()
}
}
)+ };
}
fmt! {
Binary => fmt_binary,
Display => fmt_display,
LowerHex => fmt_lower_hex,
Octal => fmt_octal,
UpperHex => fmt_upper_hex,
}
#[doc = include_str!("../doc/domain/PartialElement.md")]
pub struct PartialElement<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
{
elem: Address<M, T>,
mask: BitMask<T::Mem>,
head: BitIdx<T::Mem>,
tail: BitEnd<T::Mem>,
_ord: PhantomData<O>,
_ref: PhantomData<&'a T::Access>,
}
impl<'a, M, T, O> PartialElement<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
{
#[inline]
fn new(
elem: Address<M, T>,
head: impl Into<Option<BitIdx<T::Mem>>>,
tail: impl Into<Option<BitEnd<T::Mem>>>,
) -> Self {
let (head, tail) = (
head.into().unwrap_or(BitIdx::MIN),
tail.into().unwrap_or(BitEnd::MAX),
);
Self {
elem,
mask: O::mask(head, tail),
head,
tail,
_ord: PhantomData,
_ref: PhantomData,
}
}
#[inline]
pub fn load_value(&self) -> T::Mem {
self.elem
.pipe(|addr| unsafe { &*addr.to_const() })
.load_value()
& self.mask.into_inner()
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn head(&self) -> BitIdx<T::Mem> {
self.head
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn tail(&self) -> BitEnd<T::Mem> {
self.tail
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn bounds(&self) -> (BitIdx<T::Mem>, BitEnd<T::Mem>) {
(self.head, self.tail)
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn mask(&self) -> BitMask<T::Mem> {
self.mask
}
#[inline]
pub fn into_bitslice(self) -> Reference<'a, M, BitSlice<T, O>>
where Address<M, BitSlice<T, O>>: Referential<'a> {
unsafe {
BitSpan::new_unchecked(
self.elem,
self.head,
(self.tail.into_inner() - self.head.into_inner()) as usize,
)
}
.to_bitslice()
}
}
impl<'a, T, O> PartialElement<'a, Mut, T, O>
where
T: BitStore,
O: BitOrder,
Address<Mut, T>: Referential<'a>,
{
#[inline]
pub fn store_value(&mut self, value: T::Mem) -> T::Mem {
let this = self.access();
let prev = this.clear_bits(self.mask);
this.set_bits(self.mask & value);
prev & self.mask.into_inner()
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn invert(&mut self) -> T::Mem {
self.access().invert_bits(self.mask) & self.mask.into_inner()
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn clear(&mut self) -> T::Mem {
self.access().clear_bits(self.mask) & self.mask.into_inner()
}
#[inline]
#[cfg(not(tarpaulin_include))]
pub fn set(&mut self) -> T::Mem {
self.access().set_bits(self.mask) & self.mask.into_inner()
}
#[inline]
fn access(&self) -> &T::Access {
unsafe { &*self.elem.to_const().cast::<T::Access>() }
}
}
impl<'a, M, T, O> PartialElement<'a, M, T, O>
where
M: Mutability,
O: BitOrder,
T: 'a + BitStore + radium::Radium,
{
#[inline]
pub fn store_value_aliased(&self, value: T::Mem) -> T::Mem {
let this = unsafe { &*self.elem.to_const().cast::<T::Access>() };
let prev = this.clear_bits(self.mask);
this.set_bits(self.mask & value);
prev & self.mask.into_inner()
}
}
#[cfg(not(tarpaulin_include))]
impl<'a, T, O> Clone for PartialElement<'a, Const, T, O>
where
T: BitStore,
O: BitOrder,
Address<Const, T>: Referential<'a>,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<'a, M, T, O> Debug for PartialElement<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
{
#[inline]
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(
fmt,
"PartialElement<{} {}, {}>",
M::RENDER,
any::type_name::<T>(),
any::type_name::<O>(),
)?;
fmt.debug_struct("")
.field("elem", &self.load_value())
.field("mask", &self.mask.fmt_display())
.field("head", &self.head.fmt_display())
.field("tail", &self.tail.fmt_display())
.finish()
}
}
#[cfg(not(tarpaulin_include))]
impl<'a, M, T, O> Hash for PartialElement<'a, M, T, O>
where
M: Mutability,
T: 'a + BitStore,
O: BitOrder,
{
#[inline]
fn hash<H>(&self, hasher: &mut H)
where H: Hasher {
self.load_value().hash(hasher);
self.mask.hash(hasher);
self.head.hash(hasher);
self.tail.hash(hasher);
}
}
impl<T, O> Copy for PartialElement<'_, Const, T, O>
where
T: BitStore,
O: BitOrder,
{
}
#[cfg(test)]
mod tests {
use rand::random;
use super::*;
use crate::prelude::*;
#[test]
fn bit_domain() {
let data = BitArray::<[u32; 3], Msb0>::new(random());
let bd = data.bit_domain();
assert!(bd.enclave().is_none());
let (head, body, tail) = bd.region().unwrap();
assert_eq!(data, body);
assert!(head.is_empty());
assert!(tail.is_empty());
let bd = data[2 ..].bit_domain();
let (head, body, tail) = bd.region().unwrap();
assert_eq!(head, &data[2 .. 32]);
assert_eq!(body, &data[32 ..]);
assert!(tail.is_empty());
let bd = data[.. 94].bit_domain();
let (head, body, tail) = bd.region().unwrap();
assert!(head.is_empty());
assert_eq!(body, &data[.. 64]);
assert_eq!(tail, &data[64 .. 94]);
let bd = data[2 .. 94].bit_domain();
let (head, body, tail) = bd.region().unwrap();
assert_eq!(head, &data[2 .. 32]);
assert_eq!(body, &data[32 .. 64]);
assert_eq!(tail, &data[64 .. 94]);
let bd = data[34 .. 62].bit_domain();
assert!(bd.region().is_none());
assert_eq!(bd.enclave().unwrap(), data[34 .. 62]);
let (head, body, tail) =
BitDomain::<Const, usize, Lsb0>::default().region().unwrap();
assert!(head.is_empty());
assert!(body.is_empty());
assert!(tail.is_empty());
}
#[test]
fn domain() {
let data: [u32; 3] = random();
let bits = data.view_bits::<Msb0>();
let d = bits.domain();
assert!(d.enclave().is_none());
let (head, body, tail) = d.region().unwrap();
assert!(head.is_none());
assert!(tail.is_none());
assert_eq!(body, data);
let d = bits[2 ..].domain();
let (head, body, tail) = d.region().unwrap();
assert_eq!(head.unwrap().load_value(), (data[0] << 2) >> 2);
assert_eq!(body, &data[1 ..]);
assert!(tail.is_none());
let d = bits[.. 94].domain();
let (head, body, tail) = d.region().unwrap();
assert!(head.is_none());
assert_eq!(body, &data[.. 2]);
assert_eq!(tail.unwrap().load_value(), (data[2] >> 2) << 2);
let d = bits[2 .. 94].domain();
let (head, body, tail) = d.region().unwrap();
assert_eq!(head.unwrap().load_value(), (data[0] << 2) >> 2);
assert_eq!(body, &data[1 .. 2]);
assert_eq!(tail.unwrap().load_value(), (data[2] >> 2) << 2);
let d = bits[34 .. 62].domain();
assert!(d.region().is_none());
assert_eq!(
d.enclave().unwrap().load_value(),
((data[1] << 2) >> 4) << 2,
);
assert!(matches!(bits![].domain(), Domain::Region {
head: None,
body: &[],
tail: None,
}));
assert!(matches!(
Domain::<Const, usize, Lsb0>::default(),
Domain::Region {
head: None,
body: &[],
tail: None,
},
));
let data = core::cell::Cell::new(0u8);
let partial =
data.view_bits::<Lsb0>()[2 .. 6].domain().enclave().unwrap();
assert_eq!(partial.store_value_aliased(!0), 0);
assert_eq!(data.get(), 0b00_1111_00);
}
#[test]
fn iter() {
let bits = [0x12u8, 0x34, 0x56].view_bits::<Lsb0>();
let mut domain = bits[4 .. 12].domain();
assert_eq!(domain.len(), 2);
assert_eq!(domain.next().unwrap(), 0x10);
assert_eq!(domain.next_back().unwrap(), 0x04);
assert!(domain.next().is_none());
assert!(domain.next_back().is_none());
assert_eq!(bits[2 .. 6].domain().len(), 1);
assert_eq!(bits[18 .. 22].domain().next_back().unwrap(), 0b00_0101_00);
let mut domain = bits[4 .. 20].domain();
assert_eq!(domain.next_back().unwrap(), 0x06);
assert_eq!(domain.next_back().unwrap(), 0x34);
assert_eq!(domain.next_back().unwrap(), 0x10);
}
#[test]
#[cfg(feature = "alloc")]
fn render() {
#[cfg(not(feature = "std"))]
use alloc::format;
let data = BitArray::<u32, Msb0>::new(random());
let render = format!("{:?}", data.bit_domain());
let expected = format!(
"BitDomain::<*const u32, {}>::Region {{ head: {:?}, body: {:?}, \
tail: {:?} }}",
any::type_name::<Msb0>(),
BitSlice::<u32, Msb0>::empty(),
data.as_bitslice(),
BitSlice::<u32, Msb0>::empty(),
);
assert_eq!(render, expected);
let render = format!("{:?}", data[2 .. 30].bit_domain());
let expected = format!(
"BitDomain::<*const u32, {}>::Enclave({:?})",
any::type_name::<Msb0>(),
&data[2 .. 30],
);
assert_eq!(render, expected);
let render = format!("{:?}", data.domain());
let expected = format!(
"Domain::<*const u32, {}>::Region {{ head: None, body: {:?}, tail: \
None }}",
any::type_name::<Msb0>(),
data.as_raw_slice(),
);
assert_eq!(render, expected);
let render = format!("{:?}", data[2 .. 30].domain());
let expected = format!(
"Domain::<*const u32, {}>::Enclave",
any::type_name::<Msb0>(),
);
assert!(render.starts_with(&expected));
let partial = 0x3Cu8.view_bits::<Lsb0>()[2 .. 6]
.domain()
.enclave()
.unwrap();
let render = format!("{:?}", partial);
assert_eq!(
render,
format!(
"PartialElement<*const u8, {}> {{ elem: 60, mask: {}, head: \
{}, tail: {} }}",
any::type_name::<Lsb0>(),
partial.mask,
partial.head,
partial.tail,
),
);
}
}