// Copyright 2025 Gabriel Bjørnager Jensen.

mod seal {
	pub trait Array { }
}

use core::array;
use core::slice;
use core::slice::SliceIndex;

pub(crate) use seal::Array as SealedArray;

/// Denotes an array.
///
/// # Safety
///
/// `Self` must always be <code>\[[Self::Scalar]; [Self::LEN]\]</code>.
///
/// Furthermore, all items must behave exactly as their standard counterparts.
pub unsafe trait Array
where
	Self:
		SealedArray
		+ IntoIterator<Item = Self::Scalar>
		+ Sized,
{
	/// The scalar (element) type of the array.
	type Scalar: Sized;

	/// The length of the array, in count of elements.
	const LEN: usize;

	/// See [`array::from_fn`].
	#[must_use]
	fn from_fn<F: FnMut(usize) -> Self::Scalar>(f: F) -> Self;

	/// See [`<[_]>::get`](slice::get).
	fn get<I: SliceIndex<[Self::Scalar]>>(&self, index: I) -> Option<&I::Output>;

	/// See [`<[_]>::get_mut`](slice::get_mut).
	fn get_mut<I: SliceIndex<[Self::Scalar]>>(&mut self, index: I) -> Option<&mut I::Output>;

	/// See [`<[_]>::get_unchecked`](slice::get_unchecked).
	#[expect(clippy::missing_safety_doc)]
	unsafe fn get_unchecked<I: SliceIndex<[Self::Scalar]>>(&self, index: I) -> &I::Output;

	/// See [`<[_]>::get_unchecked_mut`](slice::get_unchecked_mut).
	#[expect(clippy::missing_safety_doc)]
	unsafe fn get_unchecked_mut<I: SliceIndex<[Self::Scalar]>>(&mut self, index: I) -> &mut I::Output;

	/// See [`array::each_ref`].
	#[must_use]
	fn each_ref(&self) -> impl Array<Scalar = &Self::Scalar>;

	/// See [`array::each_ref`].
	#[must_use]
	fn each_mut(&mut self) -> impl Array<Scalar = &mut Self::Scalar>;

	/// See [`array::map`].
	#[must_use]
	fn map<F: FnMut(Self::Scalar) -> U, U>(self, op: F) -> impl Array<Scalar = U>;

	/// See [`<[_]>::iter`](slice::iter).
	fn iter(&'_ self) -> slice::Iter<'_, Self::Scalar>;

	/// See [`<[_]>::iter_mut`](slice::iter_mut).
	fn iter_mut(&'_ mut self) -> slice::IterMut<'_, Self::Scalar>;

	/// See [`<[_; _]>::as_slice`](array::as_slice).
	#[must_use]
	fn as_slice(&self) -> &[Self::Scalar];

	/// See [`<[_; _]>::as_mut_slice`](array::as_mut_slice).
	#[must_use]
	fn as_mut_slice(&mut self) -> &mut [Self::Scalar];
}

impl<T, const N: usize> SealedArray for [T; N] { }

unsafe impl<T, const N: usize> Array for [T; N] {
	type Scalar = T;

	const LEN: usize = N;

	#[inline(always)]
	#[track_caller]
	fn from_fn<F: FnMut(usize) -> T>(f: F) -> Self {
		array::from_fn(f)
	}

	#[inline(always)]
	#[track_caller]
	fn get<I: SliceIndex<[T]>>(&self, index: I) -> Option<&I::Output> {
		self.as_slice().get(index)
	}

	#[inline(always)]
	#[track_caller]
	fn get_mut<I: SliceIndex<[T]>>(&mut self, index: I) -> Option<&mut I::Output> {
		self.as_mut_slice().get_mut(index)
	}

	#[inline(always)]
	#[track_caller]
	unsafe fn get_unchecked<I: SliceIndex<[T]>>(&self, index: I) -> &I::Output {
		unsafe { self.as_slice().get_unchecked(index) }
	}

	#[inline(always)]
	#[track_caller]
	unsafe fn get_unchecked_mut<I: SliceIndex<[T]>>(&mut self, index: I) -> &mut I::Output {
		unsafe { self.as_mut_slice().get_unchecked_mut(index) }
	}

	#[expect(refining_impl_trait_reachable)]
	#[inline(always)]
	#[track_caller]
	fn each_ref(&self) -> [&T; N] {
		self.each_ref()
	}

	#[expect(refining_impl_trait_reachable)]
	#[inline(always)]
	#[track_caller]
	fn each_mut(&mut self) -> [&mut T; N] {
		self.each_mut()
	}

	#[expect(refining_impl_trait_reachable)]
	#[inline(always)]
	#[track_caller]
	fn map<F: FnMut(Self::Scalar) -> U, U>(self, op: F) -> [U; N] {
		self.map(op)
	}

	#[allow(clippy::into_iter_on_ref)]
	#[inline(always)]
	#[track_caller]
	fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
		self.into_iter()
	}

	#[allow(clippy::into_iter_on_ref)]
	#[inline(always)]
	#[track_caller]
	fn iter_mut<'a>(&'a mut self) -> slice::IterMut<'a, T> {
		self.into_iter()
	}

	#[inline(always)]
	#[track_caller]
	fn as_slice(&self) -> &[Self::Scalar] {
		self
	}

	#[inline(always)]
	#[track_caller]
	fn as_mut_slice(&mut self) -> &mut [Self::Scalar] {
		self
	}
}
