#![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,
			),
		);
	}
}