#![doc = include_str!("../doc/index.md")]

use core::{
	any,
	fmt::{
		self,
		Binary,
		Debug,
		Display,
		Formatter,
	},
	iter::{
		FusedIterator,
		Sum,
	},
	marker::PhantomData,
	ops::{
		BitAnd,
		BitOr,
		Not,
	},
};

use crate::{
	mem::{
		bits_of,
		BitRegister,
	},
	order::BitOrder,
};

#[repr(transparent)]
#[doc = include_str!("../doc/index/BitIdx.md")]
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitIdx<R = usize>
where R: BitRegister
{
	/// Semantic index counter within a register, constrained to `0 .. R::BITS`.
	idx: u8,
	/// Marker for the register type.
	_ty: PhantomData<R>,
}

impl<R> BitIdx<R>
where R: BitRegister
{
	/// The inclusive maximum index within an `R` element.
	pub const MAX: Self = Self {
		idx: R::MASK,
		_ty: PhantomData,
	};
	/// The inclusive minimum index within an `R` element.
	pub const MIN: Self = Self {
		idx: 0,
		_ty: PhantomData,
	};

	/// Wraps a counter value as a known-good index into an `R` register.
	///
	/// ## Parameters
	///
	/// - `idx`: The counter value to mark as an index. This must be in the
	///   range `0 .. R::BITS`.
	///
	/// ## Returns
	///
	/// This returns `idx`, either marked as a valid `BitIdx` or an invalid
	/// `BitIdxError` by whether it is within the valid range `0 .. R::BITS`.
	#[inline]
	pub fn new(idx: u8) -> Result<Self, BitIdxError<R>> {
		if idx >= bits_of::<R>() as u8 {
			return Err(BitIdxError::new(idx));
		}
		Ok(unsafe { Self::new_unchecked(idx) })
	}

	/// Wraps a counter value as an assumed-good index into an `R` register.
	///
	/// ## Parameters
	///
	/// - `idx`: The counter value to mark as an index. This must be in the
	///   range `0 .. R::BITS`.
	///
	/// ## Returns
	///
	/// This unconditionally marks `idx` as a valid bit-index.
	///
	/// ## Safety
	///
	/// If the `idx` value is outside the valid range, then the program is
	/// incorrect. Debug builds will panic; release builds do not inspect the
	/// value or specify a behavior.
	#[inline]
	pub unsafe fn new_unchecked(idx: u8) -> Self {
		debug_assert!(
			idx < bits_of::<R>() as u8,
			"Bit index {} cannot exceed type width {}",
			idx,
			bits_of::<R>(),
		);
		Self {
			idx,
			_ty: PhantomData,
		}
	}

	/// Removes the index wrapper, leaving the internal counter.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn into_inner(self) -> u8 {
		self.idx
	}

	/// Increments an index counter, wrapping at the back edge of the register.
	///
	/// ## Parameters
	///
	/// - `self`: The index to increment.
	///
	/// ## Returns
	///
	/// - `.0`: The next index after `self`.
	/// - `.1`: Indicates whether the new index is in the next memory address.
	#[inline]
	pub fn next(self) -> (Self, bool) {
		let next = self.idx + 1;
		(
			unsafe { Self::new_unchecked(next & R::MASK) },
			next == bits_of::<R>() as u8,
		)
	}

	/// Decrements an index counter, wrapping at the front edge of the register.
	///
	/// ## Parameters
	///
	/// - `self`: The index to decrement.
	///
	/// ## Returns
	///
	/// - `.0`: The previous index before `self`.
	/// - `.1`: Indicates whether the new index is in the previous memory
	///   address.
	#[inline]
	pub fn prev(self) -> (Self, bool) {
		let prev = self.idx.wrapping_sub(1);
		(
			unsafe { Self::new_unchecked(prev & R::MASK) },
			self.idx == 0,
		)
	}

	/// Computes the bit position corresponding to `self` under some ordering.
	///
	/// This forwards to [`O::at::<R>`], which is the only public, safe,
	/// constructor for a position counter.
	///
	/// [`O::at::<R>`]: crate::order::BitOrder::at
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn position<O>(self) -> BitPos<R>
	where O: BitOrder {
		O::at::<R>(self)
	}

	/// Computes the bit selector corresponding to `self` under an ordering.
	///
	/// This forwards to [`O::select::<R>`], which is the only public, safe,
	/// constructor for a bit selector.
	///
	/// [`O::select::<R>`]: crate::order::BitOrder::select
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn select<O>(self) -> BitSel<R>
	where O: BitOrder {
		O::select::<R>(self)
	}

	/// Computes the bit selector for `self` as an accessor mask.
	///
	/// This is a type-cast over [`Self::select`].
	///
	/// [`Self::select`]: Self::select
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn mask<O>(self) -> BitMask<R>
	where O: BitOrder {
		self.select::<O>().mask()
	}

	/// Iterates over all indices between an inclusive start and exclusive end
	/// point.
	///
	/// Because implementation details of the range type family, including the
	/// [`RangeBounds`] trait, are not yet stable, and heterogeneous ranges are
	/// not supported, this must be an opaque iterator rather than a direct
	/// [`Range<BitIdx<R>>`].
	///
	/// # Parameters
	///
	/// - `from`: The inclusive low bound of the range. This will be the first
	///   index produced by the iterator.
	/// - `upto`: The exclusive high bound of the range. The iterator will halt
	///   before yielding an index of this value.
	///
	/// # Returns
	///
	/// An opaque iterator that is equivalent to the range `from .. upto`.
	///
	/// # Requirements
	///
	/// `from` must be no greater than `upto`.
	///
	/// [`RangeBounds`]: core::ops::RangeBounds
	/// [`Range<BitIdx<R>>`]: core::ops::Range
	#[inline]
	pub fn range(
		self,
		upto: BitEnd<R>,
	) -> impl Iterator<Item = Self>
	+ DoubleEndedIterator
	+ ExactSizeIterator
	+ FusedIterator {
		let (from, upto) = (self.into_inner(), upto.into_inner());
		debug_assert!(from <= upto, "Ranges must run from low to high");
		(from .. upto).map(|val| unsafe { Self::new_unchecked(val) })
	}

	/// Iterates over all possible index values.
	#[inline]
	pub fn range_all() -> impl Iterator<Item = Self>
	+ DoubleEndedIterator
	+ ExactSizeIterator
	+ FusedIterator {
		BitIdx::MIN.range(BitEnd::MAX)
	}

	/// Computes the jump distance for some number of bits away from a starting
	/// index.
	///
	/// This computes the number of elements by which to adjust a base pointer,
	/// and then the bit index of the destination bit in the new referent
	/// register element.
	///
	/// # Parameters
	///
	/// - `self`: An index within some element, from which the offset is
	///   computed.
	/// - `by`: The distance by which to jump. Negative values move lower in the
	///   index and element-pointer space; positive values move higher.
	///
	/// # Returns
	///
	/// - `.0`: The number of elements `R` by which to adjust a base pointer.
	///   This value can be passed directly into [`ptr::offset`].
	/// - `.1`: The index of the destination bit within the destination element.
	///
	/// [`ptr::offset`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset
	pub(crate) fn offset(self, by: isize) -> (isize, Self) {
		/* Signed-add `self.idx` to the jump distance. This will almost
		 * certainly not wrap (as the crate imposes restrictions well below
		 * `isize::MAX`), but correctness never hurts. The resulting sum is a
		 * bit distance that is then broken into an element distance and final
		 * bit index.
		 */
		let far = by.wrapping_add(self.into_inner() as isize);

		let (elts, head) = (far >> R::INDX, far as u8 & R::MASK);

		(elts, unsafe { Self::new_unchecked(head) })
	}

	/// Computes the span information for a region beginning at `self` for `len`
	/// bits.
	///
	/// The span information is the number of elements in the region that hold
	/// live bits, and the position of the tail marker after the live bits.
	///
	/// This forwards to [`BitEnd::span`], as the computation is identical for
	/// the two types. Beginning a span at any `Idx` is equivalent to beginning
	/// it at the tail of a previous span.
	///
	/// # Parameters
	///
	/// - `self`: The start bit of the span.
	/// - `len`: The number of bits in the span.
	///
	/// # Returns
	///
	/// - `.0`: The number of elements, starting in the element that contains
	///   `self`, that contain live bits of the span.
	/// - `.1`: The tail counter of the span’s end point.
	///
	/// [`BitEnd::span`]: crate::index::BitEnd::span
	pub(crate) fn span(self, len: usize) -> (usize, BitEnd<R>) {
		unsafe { BitEnd::<R>::new_unchecked(self.into_inner()) }.span(len)
	}
}

impl<R> Binary for BitIdx<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "{:0>1$b}", self.idx, R::INDX as usize)
	}
}

impl<R> Debug for BitIdx<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "BitIdx<{}>({})", any::type_name::<R>(), self)
	}
}

impl<R> Display for BitIdx<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		Binary::fmt(self, fmt)
	}
}

#[repr(transparent)]
#[doc = include_str!("../doc/index/BitIdxError.md")]
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitIdxError<R = usize>
where R: BitRegister
{
	/// The value that is invalid as a [`BitIdx<R>`].
	///
	/// [`BitIdx<R>`]: crate::index::BitIdx
	err: u8,
	/// Marker for the register type.
	_ty: PhantomData<R>,
}

impl<R> BitIdxError<R>
where R: BitRegister
{
	/// Marks a counter value as invalid to be an index for an `R` register.
	///
	/// ## Parameters
	///
	/// - `err`: The counter value to mark as an error. This must be greater
	///   than `R::BITS`.
	///
	/// ## Returns
	///
	/// This returns `err`, marked as an invalid index for `R`.
	///
	/// ## Panics
	///
	/// Debug builds panic when `err` is a valid index for `R`.
	pub(crate) fn new(err: u8) -> Self {
		debug_assert!(
			err >= bits_of::<R>() as u8,
			"Bit index {} is valid for type width {}",
			err,
			bits_of::<R>(),
		);
		Self {
			err,
			_ty: PhantomData,
		}
	}

	/// Removes the error wrapper, leaving the internal counter.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn into_inner(self) -> u8 {
		self.err
	}
}

impl<R> Debug for BitIdxError<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "BitIdxError<{}>({})", any::type_name::<R>(), self.err)
	}
}

#[cfg(not(tarpaulin_include))]
impl<R> Display for BitIdxError<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(
			fmt,
			"the value {} is too large to index into {} ({} bits wide)",
			self.err,
			any::type_name::<R>(),
			bits_of::<R>(),
		)
	}
}

#[cfg(feature = "std")]
impl<R> std::error::Error for BitIdxError<R> where R: BitRegister {}

#[repr(transparent)]
#[doc = include_str!("../doc/index/BitEnd.md")]
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitEnd<R = usize>
where R: BitRegister
{
	/// Semantic tail counter within or after a register, contained to `0 ..=
	/// R::BITS`.
	end: u8,
	/// Marker for the register type.
	_ty: PhantomData<R>,
}

impl<R> BitEnd<R>
where R: BitRegister
{
	/// The inclusive maximum tail within (or after) an `R` element.
	pub const MAX: Self = Self {
		end: bits_of::<R>() as u8,
		_ty: PhantomData,
	};
	/// The inclusive minimum tail within (or after) an `R` element.
	pub const MIN: Self = Self {
		end: 0,
		_ty: PhantomData,
	};

	/// Wraps a counter value as a known-good tail of an `R` register.
	///
	/// ## Parameters
	///
	/// - `end`: The counter value to mark as a tail. This must be in the range
	///   `0 ..= R::BITS`.
	///
	/// ## Returns
	///
	/// This returns `Some(end)` when it is in the valid range `0 ..= R::BITS`,
	/// and `None` when it is not.
	#[inline]
	pub fn new(end: u8) -> Option<Self> {
		if end > bits_of::<R>() as u8 {
			return None;
		}
		Some(unsafe { Self::new_unchecked(end) })
	}

	/// Wraps a counter value as an assumed-good tail of an `R` register.
	///
	/// ## Parameters
	///
	/// - `end`: The counter value to mark as a tail. This must be in the range
	///   `0 ..= R::BITS`.
	///
	/// ## Returns
	///
	/// This unconditionally marks `end` as a valid tail index.
	///
	/// ## Safety
	///
	/// If the `end` value is outside the valid range, then the program is
	/// incorrect. Debug builds will panic; release builds do not inspect the
	/// value or specify a behavior.
	pub(crate) unsafe fn new_unchecked(end: u8) -> Self {
		debug_assert!(
			end <= bits_of::<R>() as u8,
			"Bit tail {} cannot exceed type width {}",
			end,
			bits_of::<R>(),
		);
		Self {
			end,
			_ty: PhantomData,
		}
	}

	/// Removes the tail wrapper, leaving the internal counter.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn into_inner(self) -> u8 {
		self.end
	}

	/// Iterates over all tail indices at and after an inclusive starting point.
	///
	/// Because implementation details of the range type family, including the
	/// [`RangeBounds`] trait, are not yet stable, and heterogeneous ranges are
	/// not yet supported, this must be an opaque iterator rather than a direct
	/// [`Range<BitEnd<R>>`].
	///
	/// # Parameters
	///
	/// - `from`: The inclusive low bound of the range. This will be the first
	///   tail produced by the iterator.
	///
	/// # Returns
	///
	/// An opaque iterator that is equivalent to the range `from ..=
	/// Self::MAX`.
	///
	/// [`RangeBounds`]: core::ops::RangeBounds
	/// [`Range<BitEnd<R>>`]: core::ops::Range
	#[inline]
	pub fn range_from(
		from: BitIdx<R>,
	) -> impl Iterator<Item = Self>
	+ DoubleEndedIterator
	+ ExactSizeIterator
	+ FusedIterator {
		(from.idx ..= Self::MAX.end)
			.map(|tail| unsafe { BitEnd::new_unchecked(tail) })
	}

	/// Computes the span information for a region.
	///
	/// The computed span of `len` bits begins at `self` and extends upwards in
	/// memory. The return value is the number of memory elements that contain
	/// bits of the span, and the first dead bit after the span.
	///
	/// ## Parameters
	///
	/// - `self`: A dead bit which is used as the first live bit of the new
	///   span.
	/// - `len`: The number of live bits in the span starting at `self`.
	///
	/// ## Returns
	///
	/// - `.0`: The number of `R` elements that contain live bits in the
	///   computed span.
	/// - `.1`: The dead-bit tail index ending the computed span.
	///
	/// ## Behavior
	///
	/// If `len` is `0`, this returns `(0, self)`, as the span has no live bits.
	/// If `self` is [`BitEnd::MAX`], then the new region starts at
	/// [`BitIdx::MIN`] in the next element.
	///
	/// [`BitEnd::MAX`]: Self::MAX
	/// [`BitIdx::MIN`]: Self::MIN
	pub(crate) fn span(self, len: usize) -> (usize, Self) {
		if len == 0 {
			return (0, self);
		}

		let head = self.end & R::MASK;
		let bits_in_head = (bits_of::<R>() as u8 - head) as usize;

		if len <= bits_in_head {
			return (1, unsafe { Self::new_unchecked(head + len as u8) });
		}

		let bits_after_head = len - bits_in_head;
		let elts = bits_after_head >> R::INDX;
		let tail = bits_after_head as u8 & R::MASK;

		let is_zero = (tail == 0) as u8;
		let edges = 2 - is_zero as usize;
		(elts + edges, unsafe {
			Self::new_unchecked((is_zero << R::INDX) | tail)
		})
	}
}

impl<R> Binary for BitEnd<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "{:0>1$b}", self.end, R::INDX as usize + 1)
	}
}

impl<R> Debug for BitEnd<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "BitEnd<{}>({})", any::type_name::<R>(), self)
	}
}

impl<R> Display for BitEnd<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		Binary::fmt(self, fmt)
	}
}

#[repr(transparent)]
#[doc = include_str!("../doc/index/BitPos.md")]
// #[rustc_layout_scalar_valid_range_end(R::BITS)]
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitPos<R = usize>
where R: BitRegister
{
	/// Electrical position counter within a register, constrained to `0 ..
	/// R::BITS`.
	pos: u8,
	/// Marker for the register type.
	_ty: PhantomData<R>,
}

impl<R> BitPos<R>
where R: BitRegister
{
	/// The position value of the most significant bit in an `R` element.
	pub const MAX: Self = Self {
		pos: R::MASK,
		_ty: PhantomData,
	};
	/// The position value of the least significant bit in an `R` element.
	pub const MIN: Self = Self {
		pos: 0,
		_ty: PhantomData,
	};

	/// Wraps a counter value as a known-good position within an `R` register.
	///
	/// ## Parameters
	///
	/// - `pos`: The counter value to mark as a position. This must be in the
	///   range `0 .. R::BITS`.
	///
	/// ## Returns
	///
	/// This returns `Some(pos)` when it is in the valid range `0 .. R::BITS`,
	/// and `None` when it is not.
	#[inline]
	pub fn new(pos: u8) -> Option<Self> {
		if pos >= bits_of::<R>() as u8 {
			return None;
		}
		Some(unsafe { Self::new_unchecked(pos) })
	}

	/// Wraps a counter value as an assumed-good position within an `R`
	/// register.
	///
	/// ## Parameters
	///
	/// - `value`: The counter value to mark as a position. This must be in the
	///   range `0 .. R::BITS`.
	///
	/// ## Returns
	///
	/// This unconditionally marks `pos` as a valid bit-position.
	///
	/// ## Safety
	///
	/// If the `pos` value is outside the valid range, then the program is
	/// incorrect. Debug builds will panic; release builds do not inspect the
	/// value or specify a behavior.
	#[inline]
	pub unsafe fn new_unchecked(pos: u8) -> Self {
		debug_assert!(
			pos < bits_of::<R>() as u8,
			"Bit position {} cannot exceed type width {}",
			pos,
			bits_of::<R>(),
		);
		Self {
			pos,
			_ty: PhantomData,
		}
	}

	/// Removes the position wrapper, leaving the internal counter.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn into_inner(self) -> u8 {
		self.pos
	}

	/// Computes the bit selector corresponding to `self`.
	///
	/// This is always `1 << self.pos`.
	#[inline]
	pub fn select(self) -> BitSel<R> {
		unsafe { BitSel::new_unchecked(R::ONE << self.pos) }
	}

	/// Computes the bit selector for `self` as an accessor mask.
	///
	/// This is a type-cast over [`Self::select`].
	///
	/// [`Self::select`]: Self::select
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn mask(self) -> BitMask<R> {
		self.select().mask()
	}

	/// Iterates over all possible position values.
	pub(crate) fn range_all() -> impl Iterator<Item = Self>
	+ DoubleEndedIterator
	+ ExactSizeIterator
	+ FusedIterator {
		BitIdx::<R>::range_all()
			.map(|idx| unsafe { Self::new_unchecked(idx.into_inner()) })
	}
}

impl<R> Binary for BitPos<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "{:0>1$b}", self.pos, R::INDX as usize)
	}
}

impl<R> Debug for BitPos<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "BitPos<{}>({})", any::type_name::<R>(), self)
	}
}

impl<R> Display for BitPos<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		Binary::fmt(self, fmt)
	}
}

#[repr(transparent)]
#[doc = include_str!("../doc/index/BitSel.md")]
// #[rustc_layout_scalar_valid_range_end(R::BITS)]
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitSel<R = usize>
where R: BitRegister
{
	/// A one-hot selection mask.
	sel: R,
}

impl<R> BitSel<R>
where R: BitRegister
{
	/// Wraps a selector value as a known-good selection in an `R` register.
	///
	/// ## Parameters
	///
	/// - `sel`: A one-hot selection mask of a bit in an `R` register.
	///
	/// ## Returns
	///
	/// This returns `Some(sel)` when it is a power of two (exactly one bit set
	/// and all others cleared), and `None` when it is not.
	#[inline]
	pub fn new(sel: R) -> Option<Self> {
		if sel.count_ones() != 1 {
			return None;
		}
		Some(unsafe { Self::new_unchecked(sel) })
	}

	/// Wraps a selector value as an assumed-good selection in an `R` register.
	///
	/// ## Parameters
	///
	/// - `sel`: A one-hot selection mask of a bit in an `R` register.
	///
	/// ## Returns
	///
	/// This unconditionally marks `sel` as a one-hot bit selector.
	///
	/// ## Safety
	///
	/// If the `sel` value has zero or multiple bits set, then it is invalid to
	/// be used as a `BitSel` and the program is incorrect. Debug builds will
	/// panic; release builds do not inspect the value or specify a behavior.
	#[inline]
	pub unsafe fn new_unchecked(sel: R) -> Self {
		debug_assert!(
			sel.count_ones() == 1,
			"Selections are required to have exactly one bit set: {:0>1$b}",
			sel,
			bits_of::<R>(),
		);
		Self { sel }
	}

	/// Removes the one-hot selection wrapper, leaving the internal mask.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn into_inner(self) -> R {
		self.sel
	}

	/// Computes a bit-mask for `self`. This is a type-cast.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn mask(self) -> BitMask<R> {
		BitMask::new(self.sel)
	}

	/// Iterates over all possible selector values.
	#[inline]
	pub fn range_all() -> impl Iterator<Item = Self>
	+ DoubleEndedIterator
	+ ExactSizeIterator
	+ FusedIterator {
		BitPos::<R>::range_all().map(BitPos::select)
	}
}

impl<R> Binary for BitSel<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "{:0>1$b}", self.sel, bits_of::<R>())
	}
}

impl<R> Debug for BitSel<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "BitSel<{}>({})", any::type_name::<R>(), self)
	}
}

impl<R> Display for BitSel<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		Binary::fmt(self, fmt)
	}
}

#[repr(transparent)]
#[doc = include_str!("../doc/index/BitMask.md")]
#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct BitMask<R = usize>
where R: BitRegister
{
	/// A mask of any number of bits to select.
	mask: R,
}

impl<R> BitMask<R>
where R: BitRegister
{
	/// A full bit-mask with every bit set.
	pub const ALL: Self = Self { mask: R::ALL };
	/// An empty bit-mask with every bit cleared.
	pub const ZERO: Self = Self { mask: R::ZERO };

	/// Wraps any `R` value as a bit-mask.
	///
	/// This constructor is provided to explicitly declare that an operation is
	/// discarding the numeric value of an integer and instead using it only as
	/// a bit-mask.
	///
	/// ## Parameters
	///
	/// - `mask`: Some integer to use as a bit-mask.
	///
	/// ## Returns
	///
	/// The `mask` value wrapped as a bit-mask, with its numeric context
	/// discarded.
	///
	/// Prefer accumulating [`BitSel`] values using its `Sum` implementation.
	///
	/// ## Safety
	///
	/// The `mask` value must be computed from a set of valid bit positions in
	/// the caller’s context.
	///
	/// [`BitSel`]: crate::index::BitSel
	#[inline]
	pub fn new(mask: R) -> Self {
		Self { mask }
	}

	/// Removes the mask wrapper, leaving the internal value.
	#[inline]
	#[cfg(not(tarpaulin_include))]
	pub fn into_inner(self) -> R {
		self.mask
	}

	/// Tests if a mask contains a given selector bit.
	///
	/// ## Parameters
	///
	/// - `&self`: The mask being tested.
	/// - `sel`: A selector bit to test in `self`.
	///
	/// ## Returns
	///
	/// Whether `self` has set the bit that `sel` indicates.
	#[inline]
	pub fn test(&self, sel: BitSel<R>) -> bool {
		self.mask & sel.sel != R::ZERO
	}

	/// Inserts a selector bit into a mask.
	///
	/// ## Parameters
	///
	/// - `&mut self`: The mask being modified.
	/// - `sel`: A selector bit to insert into `self`.
	///
	/// ## Effects
	///
	/// The `sel` bit is set in the mask.
	#[inline]
	pub fn insert(&mut self, sel: BitSel<R>) {
		self.mask |= sel.sel;
	}

	/// Creates a new mask with a selector bit activated.
	///
	/// ## Parameters
	///
	/// - `self`: The original mask.
	/// - `sel`: The selector bit being added into the mask.
	///
	/// ## Returns
	///
	/// A new bit-mask with `sel` activated.
	#[inline]
	pub fn combine(self, sel: BitSel<R>) -> Self {
		Self {
			mask: self.mask | sel.sel,
		}
	}
}

impl<R> Binary for BitMask<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "{:0>1$b}", self.mask, bits_of::<R>())
	}
}

impl<R> Debug for BitMask<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		write!(fmt, "BitMask<{}>({})", any::type_name::<R>(), self)
	}
}

impl<R> Display for BitMask<R>
where R: BitRegister
{
	#[inline]
	fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
		Binary::fmt(self, fmt)
	}
}

impl<R> Sum<BitSel<R>> for BitMask<R>
where R: BitRegister
{
	#[inline]
	fn sum<I>(iter: I) -> Self
	where I: Iterator<Item = BitSel<R>> {
		iter.fold(Self::ZERO, Self::combine)
	}
}

impl<R> BitAnd<R> for BitMask<R>
where R: BitRegister
{
	type Output = Self;

	#[inline]
	fn bitand(self, rhs: R) -> Self::Output {
		Self {
			mask: self.mask & rhs,
		}
	}
}

impl<R> BitOr<R> for BitMask<R>
where R: BitRegister
{
	type Output = Self;

	#[inline]
	fn bitor(self, rhs: R) -> Self::Output {
		Self {
			mask: self.mask | rhs,
		}
	}
}

impl<R> Not for BitMask<R>
where R: BitRegister
{
	type Output = Self;

	#[inline]
	fn not(self) -> Self::Output {
		Self { mask: !self.mask }
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use crate::order::Lsb0;

	#[test]
	fn index_ctors() {
		for n in 0 .. 8 {
			assert!(BitIdx::<u8>::new(n).is_ok());
		}
		assert!(BitIdx::<u8>::new(8).is_err());

		for n in 0 .. 16 {
			assert!(BitIdx::<u16>::new(n).is_ok());
		}
		assert!(BitIdx::<u16>::new(16).is_err());

		for n in 0 .. 32 {
			assert!(BitIdx::<u32>::new(n).is_ok());
		}
		assert!(BitIdx::<u32>::new(32).is_err());

		#[cfg(target_pointer_width = "64")]
		{
			for n in 0 .. 64 {
				assert!(BitIdx::<u64>::new(n).is_ok());
			}
			assert!(BitIdx::<u64>::new(64).is_err());
		}

		for n in 0 .. bits_of::<usize>() as u8 {
			assert!(BitIdx::<usize>::new(n).is_ok());
		}
		assert!(BitIdx::<usize>::new(bits_of::<usize>() as u8).is_err());
	}

	#[test]
	fn tail_ctors() {
		for n in 0 ..= 8 {
			assert!(BitEnd::<u8>::new(n).is_some());
		}
		assert!(BitEnd::<u8>::new(9).is_none());

		for n in 0 ..= 16 {
			assert!(BitEnd::<u16>::new(n).is_some());
		}
		assert!(BitEnd::<u16>::new(17).is_none());

		for n in 0 ..= 32 {
			assert!(BitEnd::<u32>::new(n).is_some());
		}
		assert!(BitEnd::<u32>::new(33).is_none());

		#[cfg(target_pointer_width = "64")]
		{
			for n in 0 ..= 64 {
				assert!(BitEnd::<u64>::new(n).is_some());
			}
			assert!(BitEnd::<u64>::new(65).is_none());
		}

		for n in 0 ..= bits_of::<usize>() as u8 {
			assert!(BitEnd::<usize>::new(n).is_some());
		}
		assert!(BitEnd::<usize>::new(bits_of::<usize>() as u8 + 1).is_none());
	}

	#[test]
	fn position_ctors() {
		for n in 0 .. 8 {
			assert!(BitPos::<u8>::new(n).is_some());
		}
		assert!(BitPos::<u8>::new(8).is_none());

		for n in 0 .. 16 {
			assert!(BitPos::<u16>::new(n).is_some());
		}
		assert!(BitPos::<u16>::new(16).is_none());

		for n in 0 .. 32 {
			assert!(BitPos::<u32>::new(n).is_some());
		}
		assert!(BitPos::<u32>::new(32).is_none());

		#[cfg(target_pointer_width = "64")]
		{
			for n in 0 .. 64 {
				assert!(BitPos::<u64>::new(n).is_some());
			}
			assert!(BitPos::<u64>::new(64).is_none());
		}

		for n in 0 .. bits_of::<usize>() as u8 {
			assert!(BitPos::<usize>::new(n).is_some());
		}
		assert!(BitPos::<usize>::new(bits_of::<usize>() as u8).is_none());
	}

	#[test]
	fn select_ctors() {
		for n in 0 .. 8 {
			assert!(BitSel::<u8>::new(1 << n).is_some());
		}
		assert!(BitSel::<u8>::new(0).is_none());
		assert!(BitSel::<u8>::new(3).is_none());

		for n in 0 .. 16 {
			assert!(BitSel::<u16>::new(1 << n).is_some());
		}
		assert!(BitSel::<u16>::new(0).is_none());
		assert!(BitSel::<u16>::new(3).is_none());

		for n in 0 .. 32 {
			assert!(BitSel::<u32>::new(1 << n).is_some());
		}
		assert!(BitSel::<u32>::new(0).is_none());
		assert!(BitSel::<u32>::new(3).is_none());

		#[cfg(target_pointer_width = "64")]
		{
			for n in 0 .. 64 {
				assert!(BitSel::<u64>::new(1 << n).is_some());
			}
			assert!(BitSel::<u64>::new(0).is_none());
			assert!(BitSel::<u64>::new(3).is_none());
		}

		for n in 0 .. bits_of::<usize>() as u8 {
			assert!(BitSel::<usize>::new(1 << n).is_some());
		}
		assert!(BitSel::<usize>::new(0).is_none());
		assert!(BitSel::<usize>::new(3).is_none());
	}

	#[test]
	fn ranges() {
		let mut range = BitIdx::<u16>::range_all();
		assert_eq!(range.next(), BitIdx::new(0).ok());
		assert_eq!(range.next_back(), BitIdx::new(15).ok());
		assert_eq!(range.count(), 14);

		let mut range = BitEnd::<u8>::range_from(BitIdx::new(1).unwrap());
		assert_eq!(range.next(), BitEnd::new(1));
		assert_eq!(range.next_back(), BitEnd::new(8));
		assert_eq!(range.count(), 6);

		let mut range = BitPos::<u8>::range_all();
		assert_eq!(range.next(), BitPos::new(0));
		assert_eq!(range.next_back(), BitPos::new(7));
		assert_eq!(range.count(), 6);

		let mut range = BitSel::<u8>::range_all();
		assert_eq!(range.next(), BitSel::new(1));
		assert_eq!(range.next_back(), BitSel::new(128));
		assert_eq!(range.count(), 6);
	}

	#[test]
	fn index_cycle() {
		let six = BitIdx::<u8>::new(6).unwrap();
		let (seven, step) = six.next();
		assert_eq!(seven, BitIdx::new(7).unwrap());
		assert!(!step);

		let (zero, step) = seven.next();
		assert_eq!(zero, BitIdx::MIN);
		assert!(step);

		let (seven, step) = zero.prev();
		assert_eq!(seven, BitIdx::new(7).unwrap());
		assert!(step);

		let (six, step) = seven.prev();
		assert_eq!(six, BitIdx::new(6).unwrap());
		assert!(!step);

		let fourteen = BitIdx::<u16>::new(14).unwrap();
		let (fifteen, step) = fourteen.next();
		assert_eq!(fifteen, BitIdx::new(15).unwrap());
		assert!(!step);
		let (zero, step) = fifteen.next();
		assert_eq!(zero, BitIdx::MIN);
		assert!(step);
		let (fifteen, step) = zero.prev();
		assert_eq!(fifteen, BitIdx::new(15).unwrap());
		assert!(step);
		let (fourteen, step) = fifteen.prev();
		assert_eq!(fourteen, BitIdx::new(14).unwrap());
		assert!(!step);
	}

	#[test]
	fn jumps() {
		let (jump, head) = BitIdx::<u8>::new(1).unwrap().offset(2);
		assert_eq!(jump, 0);
		assert_eq!(head, BitIdx::new(3).unwrap());

		let (jump, head) = BitIdx::<u8>::MAX.offset(1);
		assert_eq!(jump, 1);
		assert_eq!(head, BitIdx::MIN);

		let (jump, head) = BitIdx::<u16>::new(10).unwrap().offset(40);
		// 10 is in 0..16; 10+40 is in 48..64
		assert_eq!(jump, 3);
		assert_eq!(head, BitIdx::new(2).unwrap());

		//  .offset() wraps at the `isize` boundary
		let (jump, head) = BitIdx::<u8>::MAX.offset(isize::MAX);
		assert_eq!(jump, -(((isize::MAX as usize + 1) >> 3) as isize));
		assert_eq!(head, BitIdx::MAX.prev().0);

		let (elts, tail) = BitIdx::<u8>::new(4).unwrap().span(0);
		assert_eq!(elts, 0);
		assert_eq!(tail, BitEnd::new(4).unwrap());

		let (elts, tail) = BitIdx::<u8>::new(3).unwrap().span(3);
		assert_eq!(elts, 1);
		assert_eq!(tail, BitEnd::new(6).unwrap());

		let (elts, tail) = BitIdx::<u16>::new(10).unwrap().span(40);
		assert_eq!(elts, 4);
		assert_eq!(tail, BitEnd::new(2).unwrap());
	}

	#[test]
	fn mask_operators() {
		let mut mask = BitIdx::<u8>::new(2)
			.unwrap()
			.range(BitEnd::new(5).unwrap())
			.map(BitIdx::select::<Lsb0>)
			.sum::<BitMask<u8>>();
		assert_eq!(mask, BitMask::new(28));
		assert_eq!(mask & 25, BitMask::new(24));
		assert_eq!(mask | 32, BitMask::new(60));
		assert_eq!(!mask, BitMask::new(!28));
		let yes = BitSel::<u8>::new(16).unwrap();
		let no = BitSel::<u8>::new(64).unwrap();
		assert!(mask.test(yes));
		assert!(!mask.test(no));
		mask.insert(no);
		assert!(mask.test(no));
	}

	#[test]
	#[cfg(feature = "alloc")]
	fn render() {
		#[cfg(not(feature = "std"))]
		use alloc::format;

		assert_eq!(format!("{:?}", BitIdx::<u8>::MAX), "BitIdx<u8>(111)");
		assert_eq!(format!("{:?}", BitIdx::<u16>::MAX), "BitIdx<u16>(1111)");
		assert_eq!(format!("{:?}", BitIdx::<u32>::MAX), "BitIdx<u32>(11111)");

		assert_eq!(
			format!("{:?}", BitIdx::<u8>::new(8).unwrap_err()),
			"BitIdxError<u8>(8)"
		);
		assert_eq!(
			format!("{:?}", BitIdx::<u16>::new(16).unwrap_err()),
			"BitIdxError<u16>(16)"
		);
		assert_eq!(
			format!("{:?}", BitIdx::<u32>::new(32).unwrap_err()),
			"BitIdxError<u32>(32)"
		);

		assert_eq!(format!("{:?}", BitEnd::<u8>::MAX), "BitEnd<u8>(1000)");
		assert_eq!(format!("{:?}", BitEnd::<u16>::MAX), "BitEnd<u16>(10000)");
		assert_eq!(format!("{:?}", BitEnd::<u32>::MAX), "BitEnd<u32>(100000)");

		assert_eq!(format!("{:?}", BitPos::<u8>::MAX), "BitPos<u8>(111)");
		assert_eq!(format!("{:?}", BitPos::<u16>::MAX), "BitPos<u16>(1111)");
		assert_eq!(format!("{:?}", BitPos::<u32>::MAX), "BitPos<u32>(11111)");

		assert_eq!(
			format!("{:?}", BitSel::<u8>::new(1).unwrap()),
			"BitSel<u8>(00000001)",
		);
		assert_eq!(
			format!("{:?}", BitSel::<u16>::new(1).unwrap()),
			"BitSel<u16>(0000000000000001)",
		);
		assert_eq!(
			format!("{:?}", BitSel::<u32>::new(1).unwrap()),
			"BitSel<u32>(00000000000000000000000000000001)",
		);

		assert_eq!(
			format!("{:?}", BitMask::<u8>::new(1 | 4 | 32)),
			"BitMask<u8>(00100101)",
		);
		assert_eq!(
			format!("{:?}", BitMask::<u16>::new(1 | 4 | 32)),
			"BitMask<u16>(0000000000100101)",
		);
		assert_eq!(
			format!("{:?}", BitMask::<u32>::new(1 | 4 | 32)),
			"BitMask<u32>(00000000000000000000000000100101)",
		);

		#[cfg(target_pointer_width = "64")]
		{
			assert_eq!(
				format!("{:?}", BitIdx::<u64>::MAX),
				"BitIdx<u64>(111111)",
			);
			assert_eq!(
				format!("{:?}", BitIdx::<u64>::new(64).unwrap_err()),
				"BitIdxError<u64>(64)",
			);
			assert_eq!(
				format!("{:?}", BitEnd::<u64>::MAX),
				"BitEnd<u64>(1000000)",
			);
			assert_eq!(
				format!("{:?}", BitPos::<u64>::MAX),
				"BitPos<u64>(111111)",
			);
			assert_eq!(
				format!("{:?}", BitSel::<u64>::new(1).unwrap()),
				"BitSel<u64>(0000000000000000000000000000000000000000000000000000000000000001)",
			);
			assert_eq!(
				format!("{:?}", BitMask::<u64>::new(1 | 4 | 32)),
				"BitMask<u64>(0000000000000000000000000000000000000000000000000000000000100101)",
			);
		}
	}
}
