use core::ops::AddAssign;
use generic_arraydeque::{ConstArrayLength, GenericArrayDeque, IntoArrayLength, typenum::Const};
use crate::utils::{PositionedChar, human_display::DisplayHuman};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InvalidHexDigits<Char, const N: usize, O = usize>(
GenericArrayDeque<PositionedChar<Char, O>, ConstArrayLength<N>>,
)
where
Const<N>: IntoArrayLength;
impl<Char, const N: usize, O> core::fmt::Display for InvalidHexDigits<Char, N, O>
where
Char: DisplayHuman,
Const<N>: IntoArrayLength,
O: core::fmt::Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut first = true;
for ch in self.iter() {
if !first {
write!(f, ", ")?;
}
write!(
f,
"'{}' at position {}",
ch.char_ref().display(),
ch.position_ref()
)?;
first = false;
}
Ok(())
}
}
impl<Char, const N: usize, O> From<PositionedChar<Char, O>> for InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn from(c: PositionedChar<Char, O>) -> Self {
Self::from_positioned_char(c)
}
}
impl<Char, const N: usize, O> From<[PositionedChar<Char, O>; 1]> for InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn from(c: [PositionedChar<Char, O>; 1]) -> Self {
let [c] = c;
Self::from_positioned_char(c)
}
}
impl<Char, const N: usize, O> InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn from_positioned_char(ch: PositionedChar<Char, O>) -> Self {
assert!(N > 0, "InvalidHexDigits capacity must be > 0");
let mut vec = GenericArrayDeque::new();
vec.push_back(ch);
Self(vec)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn from_char(pos: O, ch: Char) -> Self {
Self::from_positioned_char(PositionedChar::with_position(ch, pos))
}
pub fn from_array(chars: [PositionedChar<Char, O>; N]) -> Self {
Self(GenericArrayDeque::from_array(chars))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn try_from_iter<I>(iter: I) -> Option<Self>
where
I: IntoIterator<Item = PositionedChar<Char, O>>,
{
GenericArrayDeque::try_from_iter(iter).map(Self).ok()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn push(&mut self, ch: PositionedChar<Char, O>) -> bool {
self.0.push_back(ch).is_none()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn push_char(&mut self, pos: O, ch: Char) -> bool {
self.push(PositionedChar::with_position(ch, pos))
}
#[cfg_attr(not(tarpaulin), inline(always))]
#[allow(clippy::len_without_is_empty)]
pub const fn len(&self) -> usize {
self.0.len()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn is_full(&self) -> bool {
self.0.is_full()
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O>,
{
let mut idx = 0;
let slice = self.0.as_mut_slices().0;
while idx < slice.len() {
slice[idx].bump_position(n);
idx += 1;
}
self
}
}
impl<Char, const N: usize, O> AsRef<[PositionedChar<Char, O>]> for InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn as_ref(&self) -> &[PositionedChar<Char, O>] {
self
}
}
impl<Char, const N: usize, O> AsMut<[PositionedChar<Char, O>]> for InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn as_mut(&mut self) -> &mut [PositionedChar<Char, O>] {
self
}
}
impl<Char, const N: usize, O> core::ops::Deref for InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
type Target = [PositionedChar<Char, O>];
#[cfg_attr(not(tarpaulin), inline(always))]
fn deref(&self) -> &Self::Target {
self.0.as_slices().0
}
}
impl<Char, const N: usize, O> core::ops::DerefMut for InvalidHexDigits<Char, N, O>
where
Const<N>: IntoArrayLength,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut_slices().0
}
}