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

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

use nvec::NString;
use nvec::n_vec::TryReserveError;

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

		Ok(new)
	}

	/// Attempts to collect a substring iterator into an
	/// N-string.
	///
	/// # Errors
	///
	/// This method will return an [`Err`] instance if
	/// the provided iterator has more octets than the
	/// string can contain.
	pub fn try_from_str_iter<'a, I: IntoIterator<Item = &'a str>>(iter: I) -> Result<Self, TryReserveError> {
		let mut new = Self::new();
		new.try_extend_str(iter)?;

		Ok(new)
	}

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

		Ok(())
	}

	/// Attempts to extend the string via a string
	/// iterator.
	///
	/// # Errors
	///
	/// This method will return an [`Err`] instance if
	/// the provided iterator has more octets than the
	/// string can contain.
	///
	/// Note that even in the case of error, the string
	/// will still be extended via the whole characters
	/// from before the error, if any.
	pub fn try_extend_str<'a, I: IntoIterator<Item = &'a str>>(&mut self, iter: I) -> Result<(), TryReserveError> {
		for s in iter {
			self.try_push_str(s)?;
		}

		Ok(())
	}
}

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

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

impl<'a, const N: usize> Extend<&'a str> for NString<N> {
	#[inline]
	fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
		self.try_extend_str(iter)
			.expect("unable to extend n-string with substrings");
	}
}

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

impl<'a, const N: usize> FromIterator<&'a char> for NString<N> {
	#[expect(clippy::from_iter_instead_of_collect)]
	#[inline]
	fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
		Self::from_iter(iter.into_iter().copied())
	}
}
