// Copyright 2025 Gabriel Bjørnager Jensen.

mod test;

use core::array;
use core::borrow::{Borrow, BorrowMut};

/// Denotes an array.
///
/// This trait allows abstracting unsized arrays.
/// It provides the methods and functions provided by both [`[_; _]`](prim@array) and [`[_]`](prim@slice).
///
/// # Safety
///
/// `Self` must always be <code>\[[Self::Scalar]; [Self::LEN]\]</code>.
///
/// Furthermore, all items must behave exactly as their standard counterparts.
///
/// # Examples
///
/// Random-access arrays:
///
/// ```rust
/// use multitype::Array;
///
/// fn get_4th_element<T: Array<Scalar: Copy>>(data: T) -> Option<T::Scalar> {
///     data.as_slice().get(0x4).copied()
/// }
///
/// assert_eq!(
///     get_4th_element([0, 1, 1, 2, 3, 5]),
///     Some(3),
/// );
///
/// assert_eq!(
///     get_4th_element([3, 1, 4, 1, 6]),
///     Some(6),
/// );
///
/// assert_eq!(
///     get_4th_element([1, 6, 1, 8]),
///     None,
/// );
/// ```
pub unsafe trait Array
where
	Self:
		crate::SealedArray
		+ AsMut<[Self::Scalar]>
		+ AsRef<[Self::Scalar]>
		+ Borrow<[Self::Scalar]>
		+ BorrowMut<[Self::Scalar]>
		+ 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 [`<[_; _]>::each_mut`](array::each_mut).
	#[must_use]
	fn each_ref(&self) -> impl Array<Scalar = &Self::Scalar>;

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

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

	/// 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> crate::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)
	}

	#[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)
	}

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

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