// Copyright 2025-2026 Gabriel Bjørnager Jensen.
//
// SPDX: MIT OR Apache-2.0

//! Iteration facilities for [`NVec`].

use core::slice;
use nvec::n_vec::{IntoIter, NVec, TryReserveError};

impl<T, const N: usize> NVec<T, N> {
	/// Attempts to collect an iterator into an
	/// N-vector.
	///
	/// # Errors
	///
	/// This method will return an [`Err`] instance if
	/// the provided iterator has more octets than the
	/// vector can contain.
	pub fn try_from_iter<I: IntoIterator<Item = T>>(iter: I) -> Result<Self, TryReserveError> {
		let mut new = Self::new();
		new.try_extend(iter)?;

		Ok(new)
	}

	/// Attempts to extend the vector via an iterator.
	///
	/// # Errors
	///
	/// This method will return an [`Err`] instance if
	/// the provided iterator has more items than the
	/// vector can contain.
	///
	/// Note that even in the case of error, the vector
	/// will still be extended via the elements from
	/// before the error, if any.
	pub fn try_extend<I: IntoIterator<Item = T>>(&mut self, iter: I) -> Result<(), TryReserveError> {
		for elem in iter {
			self.try_push(elem)?;
		}

		Ok(())
	}

	/// Attempts to extend the vector via a slice.
	///
	/// The elements of the slice are cloned orderly
	/// into the vector.
	///
	/// # Errors
	///
	/// This method will return an [`Err`] instance if
	/// the provided iterator has more items than the
	/// vector can contain.
	///
	/// Note that even in the case of error, the vector
	/// will still be extended via the elements from
	/// before the error, if any.
	#[inline]
	pub fn try_extend_from_slice(&mut self, slice: &[T]) -> Result<(), TryReserveError>
	where
		T: Clone,
	{
		self.try_extend(slice.iter().cloned())
	}
}

impl<A, const N: usize> Extend<A> for NVec<A, N> {
	#[inline]
	fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
		self.try_extend(iter)
			.expect("unable to extend n-vector with iterator");
	}
}

impl<'a, A: 'a + Copy, const N: usize> Extend<&'a A> for NVec<A, N> {
	#[inline]
	fn extend<T: IntoIterator<Item = &'a A>>(&mut self, iter: T) {
		self.extend(iter.into_iter().copied())
	}
}

impl<A, const N: usize> FromIterator<A> for NVec<A, N> {
	#[inline]
	fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
		Self::try_from_iter(iter)
			.expect("unable to collect iterator into n-vector")
	}
}

impl<T, const N: usize> IntoIterator for NVec<T, N> {
	type Item = T;

	type IntoIter = IntoIter<T, N>;

	#[inline]
	fn into_iter(self) -> Self::IntoIter {
		IntoIter::new(self)
	}
}

impl<'a, T, const N: usize> IntoIterator for &'a NVec<T, N> {
	type Item = &'a T;

	type IntoIter = slice::Iter<'a, T>;

	#[inline]
	fn into_iter(self) -> Self::IntoIter {
		self.iter()
	}
}

impl<'a, T, const N: usize> IntoIterator for &'a mut NVec<T, N> {
	type Item = &'a mut T;

	type IntoIter = slice::IterMut<'a, T>;

	#[inline]
	fn into_iter(self) -> Self::IntoIter {
		self.iter_mut()
	}
}
