#![no_std]

use core::{
    fmt::Display,
    num::NonZeroU8,
    ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr},
};

use sealed::{BackingType, Index, NonZeroPrimitive, Scalar};

/// The error type for the fields' operations
#[derive(thiserror_no_std::Error, Debug)]
pub enum Error<Index> {
    /// Out-of-bounds index
    #[error(
        "Invalid index {0}: the index exceeds the maximum size ({1}) of the \
         field"
    )]
    IndexOutOfBounds(Index, Index),
    /// Size too large
    #[error("Size {0} exceeds the maximum size {1} of the field")]
    InvalidSize(Index, Index),
    /// Failed conversion from vector to bit field
    #[cfg(feature = "alloc")]
    #[error("The vector with size {0} can't fit in a bit field")]
    VectorTooLarge(Index),
    /// Failed conversion from vector to bit field
    #[cfg(feature = "alloc")]
    #[error("Cannot initialize a bit field from an empty vector")]
    EmptyVector,
}

// Sealed traits that should not be exposed to the clients of this library
mod sealed {
    use core::ops::{
        AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, Not, Shl,
        Shr, Sub,
    };

    pub trait NonZeroPrimitive: Copy {
        type ZeroablePrimitive;

        fn get(self) -> Self::ZeroablePrimitive;
    }

    pub trait BackingType {
        type Index: Index;
        type Size: NonZeroPrimitive<ZeroablePrimitive = Self::Index>;
    }

    pub trait Index:
        AddAssign + Copy + Into<usize> + Ord + Sub<Output = Self>
    {
        const ONE: Self;
        const ZERO: Self;
    }

    pub trait Scalar:
        BitAnd<Output = Self>
        + BitAndAssign
        + BitOr<Output = Self>
        + BitXor<Output = Self>
        + BitOrAssign
        + Copy
        + Eq
        + Not<Output = Self>
        + Shl<<Self as BackingType>::Index, Output = Self>
        + Shr<<Self as BackingType>::Index, Output = Self>
    {
        const BITS: u8;
        const MAX: Self;
        const ONE: Self;
        const ZERO: Self;

        fn count_ones(self) -> u8;
        fn to_max_scalar_repr(self) -> u128;
        fn from_max_scalar_repr(val: u128) -> Self;
    }
}

impl NonZeroPrimitive for NonZeroU8 {
    type ZeroablePrimitive = u8;

    fn get(self) -> Self::ZeroablePrimitive {
        self.get()
    }
}

impl Index for u8 {
    const ONE: Self = 1;
    const ZERO: Self = 0;
}

impl<T: Scalar> BackingType for T {
    type Index = u8;
    type Size = NonZeroU8;
}

macro_rules! derive_scalar {
    ( $( $primitive:ty ),* ) => {
        $(
        impl Scalar for $primitive {
            const BITS: u8 = <$primitive>::BITS as u8;
            const MAX: Self = <$primitive>::MAX;
            const ONE: Self = 1;
            const ZERO: Self = 0;

            fn count_ones(self) -> u8 {
                <$primitive>::count_ones(self) as u8
            }

            // Cast the field to the biggest scalar backing type
            fn to_max_scalar_repr(self) -> u128 {
                self as u128
            }

            // Cast the field from the biggest scalar backing type
            // SAFETY: this is a primitive type cast which will truncate the excessive bits which is the intended behavior
            fn from_max_scalar_repr(val: u128) -> Self {
                val as Self
            }
        }
)*
    };
}

derive_scalar!(u8, u16, u32, u64, u128);

/// A trait to share the bit field behavior accross different backing types
pub trait BitField:
    BitAnd
    + BitOr
    + BitXor
    + Display
    + Not
    + Shl<Self::Index>
    + Shr<Self::Index>
    + Sized
{
    type Index: Index;
    type Size: NonZeroPrimitive<ZeroablePrimitive = Self::Index>;

    /// Get the size of this bit field
    fn size(&self) -> Self::Size;
    /// Set the bit at the provided index to 1.
    ///
    /// # Errors
    ///
    /// This function fails if the provided index exceeds the size of the field
    fn set(&mut self, index: Self::Index) -> Result<(), Error<Self::Index>> {
        if index < self.size().get() {
            self.set_unchecked(index);
            Ok(())
        } else {
            Err(Error::IndexOutOfBounds(index, self.size().get()))
        }
    }
    /// Set the bit at the provided index to 1 without checking if the index is
    /// valid
    fn set_unchecked(&mut self, index: Self::Index);
    /// Set all the bits to 1
    fn set_all(&mut self);
    /// Get the bit at the provided index.
    ///
    /// # Errors
    ///
    /// This function fails if the provided index exceeds the size of the field
    fn get(&self, index: Self::Index) -> Result<bool, Error<Self::Index>> {
        if index < self.size().get() {
            Ok(self.get_unchecked(index))
        } else {
            Err(Error::IndexOutOfBounds(index, self.size().get()))
        }
    }
    /// Get the bit at the provided index without checking if the index is valid
    fn get_unchecked(&self, index: Self::Index) -> bool;
    /// Set the bit at the provided index to 0.
    ///
    /// # Errors
    ///
    /// This function fails if the provided index exceeds the size of the field
    fn clear(&mut self, index: Self::Index) -> Result<(), Error<Self::Index>> {
        if index < self.size().get() {
            self.clear_unchecked(index);
            Ok(())
        } else {
            Err(Error::IndexOutOfBounds(index, self.size().get()))
        }
    }
    /// Set the bit at the provided index to 0
    fn clear_unchecked(&mut self, index: Self::Index);
    /// Set all the bits to 0
    fn clear_all(&mut self);
    /// Get the number of bits set to 1
    fn count_ones(&self)
        -> <Self::Size as NonZeroPrimitive>::ZeroablePrimitive;
    /// Get the number of bits set to 0
    fn count_zeros(
        &self,
    ) -> <Self::Size as NonZeroPrimitive>::ZeroablePrimitive {
        self.size().get() - self.count_ones()
    }

    /// Generate an iterator over the bit field
    fn iter(&self) -> Explorer<'_, Self> {
        Explorer {
            field: self,
            ptr: Self::Index::ZERO,
        }
    }
}

/// The bit field
#[derive(Clone)]
pub struct Campo<Repr: BackingType> {
    // The representation in memory of this bit field, the first bit of the
    // field is mapped to the most significant bit of the backing type
    repr: Repr,
    // The actual length of this bitfield which could be less than the memory
    // size of the type backing this object
    size: Repr::Size,
}

impl<Repr: BackingType + Copy> Copy for Campo<Repr> {}

/// An iterator for the [`Campo`] bit field
pub struct Explorer<'field, C: BitField> {
    field: &'field C,
    ptr: C::Index,
}

impl<Repr: BitField> Iterator for Explorer<'_, Repr> {
    type Item = bool;

    fn next(&mut self) -> Option<Self::Item> {
        self.field.get(self.ptr).ok().inspect(|_| {
            // SAFETY: the scalar fields top at 128 bits of length so no chance
            // to overflow this addition. For the vectorized field we can expect
            // to never reach a size matching the amount of addressable memory
            self.ptr += Repr::Index::ONE;
        })
    }
}

impl<Repr: BackingType> Display for Campo<Repr>
where
    Campo<Repr>: BitField,
{
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        for bit in self.iter().take(self.size.get().into()) {
            write!(f, "{}", bit as u8)?;
        }

        core::fmt::Result::Ok(())
    }
}

impl<Repr: Scalar> BitAnd for Campo<Repr> {
    type Output = Self;

    /// Performs the [`&`] operation. The size of the resulting [`Campo`] is
    /// the minimum between the two inputs.
    fn bitand(self, rhs: Self) -> Self::Output {
        Self {
            repr: self.repr & rhs.repr,
            size: self.size.min(rhs.size),
        }
    }
}

impl<Repr: Scalar> BitOr for Campo<Repr> {
    type Output = Self;

    /// Performs the [`|`] operation. The size of the resulting [`Campo`] is
    /// the minimum between the two inputs.
    fn bitor(self, rhs: Self) -> Self::Output {
        Self {
            repr: self.repr | rhs.repr,
            size: self.size.min(rhs.size),
        }
    }
}

impl<Repr: Scalar> BitXor for Campo<Repr> {
    type Output = Self;

    /// Performs the [`^`] operation. The size of the resulting [`Campo`] is
    /// the minimum between the two inputs.
    fn bitxor(self, rhs: Self) -> Self::Output {
        Self {
            repr: self.repr ^ rhs.repr,
            size: self.size.min(rhs.size),
        }
    }
}

impl<Repr: Scalar> Not for Campo<Repr> {
    type Output = Self;

    fn not(self) -> Self::Output {
        Self {
            repr: !self.repr,
            size: self.size,
        }
    }
}

impl<Repr: Scalar> Shl<<Self as BitField>::Index> for Campo<Repr> {
    type Output = Self;

    /// Performs the `<<` operation which shifts the bits of the field towards
    /// higher indexes.
    fn shl(self, rhs: <Self as BitField>::Index) -> Self::Output {
        Self {
            repr: self.repr << rhs,
            size: self.size,
        }
    }
}

impl<Repr: Scalar> Shr<<Self as BitField>::Index> for Campo<Repr> {
    type Output = Self;

    /// Performs the `>>` operation which shifts the bits of the field towards
    /// lower indexes.
    fn shr(self, rhs: <Self as BitField>::Index) -> Self::Output {
        // Before shifting the field towards lower indexes, clean the bits past
        // the field's size. These might dirty from previous operations and need
        // to be nullified before they are moved to the set of valid bits
        let new_repr = self.repr & !(Repr::MAX << self.size.get());
        Self {
            repr: new_repr >> rhs,
            size: self.size,
        }
    }
}

impl<Repr: Scalar> BitField for Campo<Repr> {
    type Index = <Repr as BackingType>::Index;
    type Size = <Repr as BackingType>::Size;

    fn size(&self) -> Self::Size {
        self.size
    }

    fn set_unchecked(&mut self, index: Self::Index) {
        self.repr |= Repr::ONE << index;
    }

    fn set_all(&mut self) {
        self.repr = Repr::MAX;
    }

    fn get_unchecked(&self, index: Self::Index) -> bool {
        (self.repr & (Repr::ONE << index)) != Repr::ZERO
    }

    fn clear_unchecked(&mut self, index: Self::Index) {
        self.repr &= !(Repr::ONE << index);
    }

    fn clear_all(&mut self) {
        self.repr = Repr::ZERO;
    }

    fn count_ones(
        &self,
    ) -> <Self::Size as NonZeroPrimitive>::ZeroablePrimitive {
        (self.repr << (Repr::BITS - self.size.get())).count_ones()
    }
}

impl<Repr: Scalar> Campo<Repr> {
    /// Create a new scalar bit field.
    ///
    /// # Errors
    ///
    /// Fails if the provided size exceeds the size of the backing type.
    pub fn new(
        size: NonZeroU8,
    ) -> Result<Self, Error<<<Repr as BackingType>::Size as NonZeroPrimitive>::ZeroablePrimitive>>{
        if size.get() <= Repr::BITS {
            Ok(Campo {
                repr: Repr::ZERO,
                size,
            })
        } else {
            Err(Error::InvalidSize(size.get(), Repr::BITS))
        }
    }

    /// Resizes the field in place to the new provided size.
    ///
    /// # Errors
    ///
    /// Fails if the new size exceeds the size of the backing type.
    pub fn resize_in_place(
        &mut self,
        size: NonZeroU8,
    ) -> Result<(), Error<<<Repr as BackingType>::Size as NonZeroPrimitive>::ZeroablePrimitive>>{
        if size.get() <= Repr::BITS {
            // Before enlarging the field, clean the bits past the field's size.
            // These might be dirty from previous operations and need to be
            // nullified before they are moved to the set of valid bits
            self.repr &= !(Repr::MAX << self.size.get());
            self.size = size;
            Ok(())
        } else {
            Err(Error::InvalidSize(size.get(), Repr::BITS))
        }
    }

    /// Resizes the field to the provided length by consuming the current field
    /// and creating a new one with the appropriate backing type.
    ///
    /// # Errors
    ///
    /// Fails if the new size exceeds the size of the new backing type.
    pub fn resize<NewRepr: Scalar>(
        self,
        target_size: NonZeroU8,
    ) -> Result<Campo<NewRepr>, Error<<<NewRepr as BackingType>::Size as NonZeroPrimitive>::ZeroablePrimitive>>{
        let mut field = Campo::<NewRepr>::new(target_size)?;
        // Before enlarging the field, clean the bits past the field's size.
        // These might be dirty from previous operations and need to be
        // nullified before they are moved to the set of valid bits
        let new_repr = self.repr & !(Repr::MAX << self.size.get());
        field.repr =
            NewRepr::from_max_scalar_repr(new_repr.to_max_scalar_repr());

        Ok(field)
    }
}

impl<Repr: Scalar> From<Repr> for Campo<Repr> {
    fn from(value: Repr) -> Self {
        Self {
            repr: value,
            size: unsafe { NonZeroU8::new_unchecked(Repr::BITS) },
        }
    }
}

#[cfg(feature = "alloc")]
#[macro_use]
extern crate alloc;

#[cfg(feature = "alloc")]
mod alloc_field {
    use core::num::NonZeroUsize;
    use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};

    use crate::{BackingType, BitField, Campo, Error, Index, NonZeroPrimitive};
    use alloc::vec::Vec;

    const EMPTY_FIELD_ERR: &str = "The Bitfield should never be empty";

    impl Index for usize {
        const ONE: Self = 1;
        const ZERO: Self = 0;
    }

    impl NonZeroPrimitive for NonZeroUsize {
        type ZeroablePrimitive = usize;

        fn get(self) -> Self::ZeroablePrimitive {
            self.get()
        }
    }

    impl BackingType for Vec<u8> {
        type Index = usize;
        type Size = NonZeroUsize;
    }

    // The bit order within a single word is the same as the scalar version of
    // [`Campo`]. The byte order is little-endian
    impl BitField for Campo<Vec<u8>> {
        type Index = <Vec<u8> as BackingType>::Index;
        type Size = <Vec<u8> as BackingType>::Size;

        fn size(&self) -> Self::Size {
            self.size
        }

        /// Set the bit at the provided index to 1 without checking if the index
        /// is valid
        ///
        /// # Panics
        ///
        /// Panics if the provided `index` maps to an out of bounds index in
        /// the underlying vector.
        fn set_unchecked(&mut self, index: Self::Index) {
            const MASK: u8 = 1;

            let word_index = index / (u8::BITS as usize);
            let word = &mut self.repr[word_index];
            let bit_index = index % (u8::BITS as usize);

            *word |= MASK << bit_index;
        }

        fn set_all(&mut self) {
            self.repr.fill(u8::MAX);
        }

        /// Get the bit at the provided index without checking if the index is
        /// valid
        ///
        /// # Panics
        ///
        /// Panics if the provided `index` maps to an out of bounds index in the
        /// underlying vector.
        fn get_unchecked(&self, index: Self::Index) -> bool {
            const MASK: u8 = 1;

            let word_index = index / (u8::BITS as usize);
            let word = &self.repr[word_index];
            let bit_index = index % (u8::BITS as usize);

            (word & (MASK << bit_index)) != 0
        }

        /// Set the bit at the provided index to 0
        ///
        /// # Panics
        ///
        /// Panics if the provided `index` maps to an out of bounds index in the
        /// underlying vector.
        fn clear_unchecked(&mut self, index: Self::Index) {
            const MASK: u8 = 1;

            let word_index = index / (u8::BITS as usize);
            let word = &mut self.repr[word_index];
            let bit_index = index % (u8::BITS as usize);

            *word &= !(MASK << bit_index);
        }

        fn clear_all(&mut self) {
            self.repr.fill(0)
        }

        fn count_ones(
            &self,
        ) -> <Self::Size as NonZeroPrimitive>::ZeroablePrimitive {
            let mut acc = 0;

            let iter = self.repr.iter().rev().skip(1);
            for word in iter {
                acc += word.count_ones() as usize;
            }

            // The last word of the collection has to be handled differently
            // since it's subject to the size constraint
            let last_word = self.repr.last().expect(EMPTY_FIELD_ERR);
            let size = self.size.get() % (u8::BITS as usize);
            let size = if size == 0 { u8::BITS as usize } else { size };
            acc +=
                (last_word << (u8::BITS as usize - size)).count_ones() as usize;

            acc
        }
    }

    impl Campo<Vec<u8>> {
        /// Create a new bit field backed by a vector.
        pub fn new(size: NonZeroUsize) -> Self {
            let required_bytes = size.get().div_ceil(u8::BITS as usize);
            let repr = vec![0; required_bytes];

            Campo { repr, size }
        }

        /// Resize the field to the new provided size
        pub fn resize(&mut self, size: NonZeroUsize) {
            const MASK: u8 = u8::MAX;

            // Before enlarging the field, clean the bits past the field's size
            // in the last word. These might be dirty from previous operations
            // and need to be nullified before they are moved to the set of
            // valid bits
            let rmndr = size.get() % (u8::BITS as usize);
            let last_word = self.repr.last_mut().expect(EMPTY_FIELD_ERR);
            *last_word &= !(MASK << rmndr);

            let required_bytes = size.get().div_ceil(u8::BITS as usize);
            self.repr.resize(required_bytes, 0);
            self.size = size;
        }

        fn bitwise_helper(
            self,
            rhs: Self,
            bwfn: impl Fn(&u8, &u8) -> u8,
        ) -> Self {
            const MASK: u8 = u8::MAX;

            let (mut shorter_field, longer_field) = if self.size <= rhs.size {
                (self, rhs)
            } else {
                (rhs, self)
            };

            // Bitwise-and until we run out of the shortest field
            for (lhs_word, rhs_word) in
                shorter_field.repr.iter_mut().zip(longer_field.repr.iter())
            {
                *lhs_word = bwfn(lhs_word, rhs_word);
            }

            // Adjust the last word based on the actual size
            let bit_index = shorter_field.size.get() % (u8::BITS as usize);
            let last_word =
                shorter_field.repr.last_mut().expect(EMPTY_FIELD_ERR);
            *last_word &= !(MASK << bit_index);

            shorter_field
        }
    }

    impl TryFrom<Vec<u8>> for Campo<Vec<u8>> {
        type Error = Error<<<Vec<u8> as BackingType>::Size as NonZeroPrimitive>::ZeroablePrimitive>;

        fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
            Ok(Self {
                size: NonZeroUsize::new(
                    value
                        .len()
                        .checked_mul(u8::BITS as usize)
                        .ok_or(Self::Error::VectorTooLarge(value.len()))?,
                )
                .ok_or(Self::Error::EmptyVector)?,
                repr: value,
            })
        }
    }

    impl BitAnd for Campo<Vec<u8>> {
        type Output = Self;

        /// Performs the [`&`] operation. The size of the resulting [`Campo`]
        /// is the minimum between the two inputs.
        fn bitand(self, rhs: Self) -> Self::Output {
            self.bitwise_helper(rhs, |lhs: &u8, rhs: &u8| -> u8 { lhs & rhs })
        }
    }

    impl BitOr for Campo<Vec<u8>> {
        type Output = Self;

        /// Performs the [`|`] operation. The size of the resulting [`Campo`]
        /// is the minimum between the two inputs.
        fn bitor(self, rhs: Self) -> Self::Output {
            self.bitwise_helper(rhs, |lhs: &u8, rhs: &u8| -> u8 { lhs | rhs })
        }
    }

    impl BitXor for Campo<Vec<u8>> {
        type Output = Self;

        /// Performs the [`^`] operation. The size of the resulting [`Campo`]
        /// is the minimum between the two inputs.
        fn bitxor(self, rhs: Self) -> Self::Output {
            self.bitwise_helper(rhs, |lhs: &u8, rhs: &u8| -> u8 { lhs ^ rhs })
        }
    }

    impl Not for Campo<Vec<u8>> {
        type Output = Self;

        fn not(mut self) -> Self::Output {
            for word in &mut self.repr {
                *word = !*word;
            }
            self
        }
    }

    impl Shl<<Self as BitField>::Index> for Campo<Vec<u8>> {
        type Output = Self;

        /// Performs the `<<` operation which shifts the bits of the field
        /// towards higher indexes.
        fn shl(mut self, rhs: <Self as BitField>::Index) -> Self::Output {
            // If the shift amount exceeds the size of a word we first need to
            // shift the vector's entries
            let words_rhs = rhs / u8::BITS as usize;
            self.repr.rotate_right(words_rhs);
            for word in self.repr.iter_mut().take(words_rhs) {
                // Now clear the first entries which are the new ones coming in
                // from the shift operation
                *word = 0;
            }

            let bits_rhs = rhs % u8::BITS as usize;
            // If the amount of the shift is a multiple of 8 we don't need to do
            // anything else
            if bits_rhs != 0 {
                let inv_rhs = u8::BITS as usize - bits_rhs;
                let mut carry = 0u8;

                for word in &mut self.repr.iter_mut().skip(words_rhs) {
                    let next_carry = *word >> inv_rhs;

                    *word <<= bits_rhs;
                    *word |= carry;
                    carry = next_carry;
                }
            }

            self
        }
    }

    impl Shr<<Self as BitField>::Index> for Campo<Vec<u8>> {
        type Output = Self;

        /// Performs the `>>` operation which shifts the bits of the field
        /// towards lower indexes.
        fn shr(mut self, rhs: <Self as BitField>::Index) -> Self::Output {
            // Before shifting the field towards lower indexes, clean the bits
            // past the field's size in the last word. These might be dirty from
            // previous operations and need to be nullified before they are
            // moved to the set of valid bits
            let last_word_size = self.size.get() % u8::BITS as usize;
            *self.repr.last_mut().expect(EMPTY_FIELD_ERR) &=
                !(u8::MAX << last_word_size);

            // If the shift amount exceeds the size of a word we first need to
            // shift the vector's entries
            let words_rhs = rhs / u8::BITS as usize;
            self.repr.rotate_left(words_rhs);
            for word in self.repr.iter_mut().rev().take(words_rhs) {
                // Now clear the last entries which are the new ones coming in
                // from the shift operation
                *word = 0;
            }

            let bits_rhs = rhs % u8::BITS as usize;
            // If the amount of the shift is a multiple of 8 we don't need to do
            // anything else
            if bits_rhs != 0 {
                let inv_rhs = u8::BITS as usize - bits_rhs;
                let mut carry = 0u8;

                for word in &mut self.repr.iter_mut().rev().skip(words_rhs) {
                    let next_carry = *word << inv_rhs;

                    *word >>= bits_rhs;
                    *word |= carry;
                    carry = next_carry;
                }
            }

            self
        }
    }
}

#[cfg(test)]
mod tests_scalar {
    use core::num::NonZeroU8;

    use crate::{BitField, Campo};

    // The scalar constructor returns an error when the size is incompatible
    // with the backing type
    #[test]
    fn scalar_constructor_fails_if_size_too_large() {
        assert!(Campo::<u8>::new(NonZeroU8::new(8).unwrap()).is_ok());
        assert!(Campo::<u8>::new(NonZeroU8::new(9).unwrap()).is_err());

        assert!(Campo::<u16>::new(NonZeroU8::new(16).unwrap()).is_ok());
        assert!(Campo::<u16>::new(NonZeroU8::new(17).unwrap()).is_err());

        assert!(Campo::<u32>::new(NonZeroU8::new(32).unwrap()).is_ok());
        assert!(Campo::<u32>::new(NonZeroU8::new(33).unwrap()).is_err());

        assert!(Campo::<u64>::new(NonZeroU8::new(64).unwrap()).is_ok());
        assert!(Campo::<u64>::new(NonZeroU8::new(65).unwrap()).is_err());

        assert!(Campo::<u128>::new(NonZeroU8::new(128).unwrap()).is_ok());
        assert!(Campo::<u128>::new(NonZeroU8::new(129).unwrap()).is_err());
    }

    // The resize_in_place method fails if the new size is too large and that no
    // changes are applied in this case
    #[test]
    fn resize_in_place_fails_if_size_too_large() {
        let mut field = Campo::<u32>::new(NonZeroU8::new(18).unwrap()).unwrap();

        assert!(field.resize_in_place(NonZeroU8::new(19).unwrap()).is_ok());
        assert_eq!(field.size.get(), 19);
        assert!(field.resize_in_place(NonZeroU8::new(33).unwrap()).is_err());
        assert_eq!(field.size.get(), 19);
    }

    // The resize_in_place method clears the new extra bits when growing in size
    #[test]
    fn resize_in_place_cleans_extra_bits() {
        let mut field = Campo::<u8>::new(NonZeroU8::new(5).unwrap()).unwrap();
        field.repr |= 0b00100000;
        assert!(field.get_unchecked(5));

        assert!(field.resize_in_place(NonZeroU8::new(7).unwrap()).is_ok());
        assert!(!field.get_unchecked(5));
    }

    // The resize method clears the new extra bits when growing in size
    #[test]
    fn resize_cleans_extra_bits() {
        let mut field = Campo::<u8>::new(NonZeroU8::new(5).unwrap()).unwrap();
        field.set_unchecked(5);
        assert!(field.get_unchecked(5));

        let new_field: Campo<u16> =
            field.resize(NonZeroU8::new(9).unwrap()).unwrap();
        assert!(!new_field.get_unchecked(5));
    }
}

#[cfg(test)]
mod tests_scalar_bitfield {
    use core::num::NonZeroU8;

    use crate::{BitField, Campo};

    #[test]
    fn set_and_get() {
        let mut field = Campo::<u32>::new(NonZeroU8::new(30).unwrap()).unwrap();

        assert!(!field.get(10).unwrap());
        assert!(field.get(50).is_err());

        assert!(field.set(10).is_ok());
        assert!(field.set(50).is_err());
        assert!(field.get(10).unwrap());
    }

    #[test]
    fn set_and_get_unchecked() {
        let mut field =
            Campo::<u128>::new(NonZeroU8::new(127).unwrap()).unwrap();

        assert!(!field.get_unchecked(126));

        field.set_unchecked(126);
        assert!(field.get(126).unwrap());
    }

    #[test]
    fn set_all() {
        let mut field = Campo::<u64>::new(NonZeroU8::new(64).unwrap()).unwrap();

        let iterator = field.iter();
        for bit in iterator {
            assert!(!bit);
        }
        field.set_all();

        let iterator = field.iter();
        for bit in iterator {
            assert!(bit);
        }
    }

    #[test]
    fn clear() {
        let mut field = Campo::<u16>::new(NonZeroU8::new(15).unwrap()).unwrap();

        assert!(!field.get(14).unwrap());
        assert!(field.set(14).is_ok());
        assert!(field.get(14).unwrap());

        assert!(field.clear(15).is_err());
        assert!(field.clear(14).is_ok());
        assert!(!field.get(14).unwrap());
    }

    #[test]
    fn clear_unchecked() {
        let mut field = Campo::<u16>::new(NonZeroU8::new(15).unwrap()).unwrap();

        assert!(!field.get(14).unwrap());
        assert!(field.set(14).is_ok());
        assert!(field.get(14).unwrap());

        field.clear_unchecked(14);
        assert!(!field.get(14).unwrap());
    }

    #[test]
    fn clear_all() {
        let mut field = Campo::<u32>::new(NonZeroU8::new(32).unwrap()).unwrap();

        field.set_all();
        let iterator = field.iter();
        for bit in iterator {
            assert!(bit);
        }

        field.clear_all();
        let iterator = field.iter();
        for bit in iterator {
            assert!(!bit);
        }
    }

    #[test]
    fn count_ones_and_zeros() {
        let mut field = Campo::<u8>::new(NonZeroU8::new(8).unwrap()).unwrap();
        assert_eq!(field.count_ones(), 0);
        assert_eq!(field.count_zeros(), 8);

        field.set_all();
        assert_eq!(field.count_ones(), 8);
        assert_eq!(field.count_zeros(), 0);
    }

    #[test]
    fn shift_right_clears_dirty_bit() {
        let mut field =
            Campo::<u128>::new(NonZeroU8::new(70).unwrap()).unwrap();

        field.set_unchecked(14);
        field.set_unchecked(40);
        field.set_unchecked(55);
        // Test a dirty bit past the field size that must be nullified during
        // the shift
        field.set_unchecked(100);

        field = field >> 35;
        assert!(field.get_unchecked(5));
        assert!(field.get_unchecked(20));
        assert!(!field.get_unchecked(65));
    }
}

#[cfg(feature = "alloc")]
#[cfg(test)]
mod tests_vectorized {
    use crate::BitField;
    use crate::Campo;
    use alloc::string::ToString;
    use alloc::vec::Vec;
    use core::num::NonZeroUsize;

    #[test]
    fn from_vector() {
        let maybe_field: Result<Campo<Vec<u8>>, _> = vec![].try_into();
        assert!(maybe_field.is_err());

        let maybe_field: Result<Campo<Vec<u8>>, _> = vec![1, 2, 3].try_into();
        assert!(maybe_field.is_ok());
    }

    // The vectorized resize method clears the new extra bits when growing in
    // size
    #[test]
    fn resize_cleans_extra_bits() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(300).unwrap());
        field.set_unchecked(301);
        assert!(field.get_unchecked(301));

        field.resize(NonZeroUsize::new(400).unwrap());
        assert!(!field.get_unchecked(301));
    }

    #[test]
    fn display() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(10).unwrap());
        field.set_unchecked(0);
        field.set_unchecked(8);
        field.set_unchecked(9);

        assert_eq!(field.to_string(), "1000000011");
    }

    #[test]
    fn bitand() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(10).unwrap());
        field.set_unchecked(0);
        field.set_unchecked(7);
        field.set_unchecked(9);

        let mut other_field =
            Campo::<Vec<u8>>::new(NonZeroUsize::new(15).unwrap());
        other_field.set_unchecked(0);
        other_field.set_unchecked(7);
        other_field.set_unchecked(15);

        let res = field & other_field;
        assert_eq!(res.size().get(), 10);
        assert!(res.get_unchecked(0));
        assert!(res.get_unchecked(7));
        assert!(!res.get_unchecked(9));
    }

    #[test]
    fn bitor() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(10).unwrap());
        field.set_unchecked(0);
        field.set_unchecked(7);
        field.set_unchecked(9);

        let mut other_field =
            Campo::<Vec<u8>>::new(NonZeroUsize::new(15).unwrap());
        other_field.set_unchecked(0);
        other_field.set_unchecked(8);
        other_field.set_unchecked(15);

        let res = field | other_field;
        assert_eq!(res.size().get(), 10);
        assert!(res.get_unchecked(0));
        assert!(res.get_unchecked(7));
        assert!(res.get_unchecked(8));
        assert!(res.get_unchecked(9));
    }

    #[test]
    fn bitxor() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(10).unwrap());
        field.set_unchecked(0);
        field.set_unchecked(7);
        field.set_unchecked(9);

        let mut other_field =
            Campo::<Vec<u8>>::new(NonZeroUsize::new(15).unwrap());
        other_field.set_unchecked(0);
        other_field.set_unchecked(8);
        other_field.set_unchecked(15);

        let res = field ^ other_field;
        assert_eq!(res.size().get(), 10);
        assert!(!res.get_unchecked(0));
        assert!(res.get_unchecked(7));
        assert!(res.get_unchecked(8));
        assert!(res.get_unchecked(9));
    }

    #[test]
    fn shift_right() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(10).unwrap());
        field.set_unchecked(0);
        field.set_unchecked(7);
        field.set_unchecked(9);
        // Test a dirty bit past the field size that must be nullified during
        // the shift
        field.set_unchecked(15);

        let res = field.clone() >> 6;
        assert!(res.get_unchecked(1));
        assert!(res.get_unchecked(3));
        assert!(!res.get_unchecked(9));

        let res = field.clone() >> 8;
        assert!(res.get_unchecked(1));
        assert!(!res.get_unchecked(7));

        let res = field.clone() >> 9;
        assert!(res.get_unchecked(0));
        assert!(!res.get_unchecked(6));

        let res = field.clone() >> 10;
        assert!(!res.get_unchecked(5));

        let res = field.clone() >> 11;
        assert!(!res.get_unchecked(4));
    }

    #[test]
    fn shift_left() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(10).unwrap());
        field.set_unchecked(0);
        field.set_unchecked(2);
        field.set_unchecked(9);

        let res = field.clone() << 6;
        assert!(res.get_unchecked(6));
        assert!(res.get_unchecked(8));
        assert!(res.get_unchecked(15));

        let res = field.clone() << 8;
        assert!(res.get_unchecked(8));
        assert!(res.get_unchecked(10));

        let res = field.clone() << 9;
        assert!(res.get_unchecked(9));
        assert!(res.get_unchecked(11));

        let res = field.clone() << 10;
        assert!(res.get_unchecked(10));
        assert!(res.get_unchecked(12));

        let res = field.clone() << 11;
        assert!(res.get_unchecked(11));
        assert!(res.get_unchecked(13));
    }
}

#[cfg(feature = "alloc")]
#[cfg(test)]
mod tests_vectorized_bitfield {
    use alloc::vec::Vec;
    use core::num::NonZeroUsize;

    use crate::{BitField, Campo};

    #[test]
    fn set_and_get() {
        // Test both a precise multiple of 8 bits and a size with a remainder
        for size in [303, 304] {
            let mut field =
                Campo::<Vec<u8>>::new(NonZeroUsize::new(size).unwrap());

            assert!(!field.get(size - 1).unwrap());
            assert!(field.get(size).is_err());

            assert!(field.set(size - 1).is_ok());
            assert!(field.set(size).is_err());
            assert!(field.get(size - 1).unwrap());
        }
    }

    #[test]
    fn set_and_get_unchecked() {
        // Test both a precise multiple of 8 bits and a size with a remainder
        for size in [527, 528] {
            let mut field =
                Campo::<Vec<u8>>::new(NonZeroUsize::new(size).unwrap());

            if size % 8 != 0 {
                assert!(!field.get_unchecked(size));
            }

            field.set_unchecked(size - 1);
            assert!(field.get(size - 1).unwrap());
        }
    }

    #[test]
    fn set_all() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(664).unwrap());

        let iterator = field.iter();
        for bit in iterator {
            assert!(!bit);
        }
        field.set_all();

        let iterator = field.iter();
        for bit in iterator {
            assert!(bit);
        }
    }

    #[test]
    fn clear() {
        // Test both a precise multiple of 8 bits and a size with a remainder
        for size in [415, 416] {
            let mut field =
                Campo::<Vec<u8>>::new(NonZeroUsize::new(size).unwrap());

            assert!(!field.get(size - 1).unwrap());
            assert!(field.set(size - 1).is_ok());
            assert!(field.get(size - 1).unwrap());

            assert!(field.clear(size).is_err());
            assert!(field.clear(size - 1).is_ok());
            assert!(!field.get(size - 1).unwrap());
        }
    }

    #[test]
    fn clear_unchecked() {
        // Test both a precise multiple of 8 bits and a size with a remainder
        for size in [815, 816] {
            let mut field =
                Campo::<Vec<u8>>::new(NonZeroUsize::new(size).unwrap());

            assert!(!field.get(size - 1).unwrap());
            assert!(field.set(size - 1).is_ok());
            assert!(field.get(size - 1).unwrap());

            field.clear_unchecked(size - 1);
            assert!(!field.get(size - 1).unwrap());
        }
    }

    #[test]
    fn clear_all() {
        let mut field = Campo::<Vec<u8>>::new(NonZeroUsize::new(932).unwrap());

        field.set_all();
        let iterator = field.iter();
        for bit in iterator {
            assert!(bit);
        }

        field.clear_all();
        let iterator = field.iter();
        for bit in iterator {
            assert!(!bit);
        }
    }

    #[test]
    fn count_ones_and_zeros() {
        // Test both a precise multiple of 8 bits and a size with a remainder
        for size in [1007, 1008] {
            let mut field =
                Campo::<Vec<u8>>::new(NonZeroUsize::new(size).unwrap());
            assert_eq!(field.count_ones(), 0);
            assert_eq!(field.count_zeros(), size);

            field.set_all();
            assert_eq!(field.count_ones(), size);
            assert_eq!(field.count_zeros(), 0);
        }
    }
}
