#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use core::{
cmp::Ordering,
hash::{Hash, Hasher},
iter::FusedIterator,
ops::{Index, Range},
slice::SliceIndex,
};
#[cfg(feature = "std")]
use std::backtrace::Backtrace;
#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::{boxed::Box, vec::Vec};
#[derive(Debug, Clone, Copy, Eq)]
pub struct ArraySection<T, const N: usize> {
start: usize,
end: usize,
array: [T; N],
}
impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl<const N: usize, const M: usize, T: PartialOrd> PartialOrd<ArraySection<T, M>>
for ArraySection<T, N>
{
#[inline]
fn partial_cmp(&self, other: &ArraySection<T, M>) -> Option<Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<const N: usize, T> ArraySection<T, N> {
#[inline]
pub const fn new(array: [T; N], section: Range<usize>) -> Self {
assert!(
section.start < N && section.end <= N,
"the sub-range must be in bounds"
);
if section.start > section.end {
Self {
start: 0,
end: 0,
array,
}
} else {
Self {
start: section.start,
end: section.end,
array,
}
}
}
#[inline]
pub const fn start(&self) -> usize {
self.start
}
#[inline]
pub const fn end(&self) -> usize {
self.end
}
#[inline]
pub fn change_section(&mut self, section: Range<usize>) {
assert!(
section.start < N && section.end <= N,
"the section must be in bounds"
);
if section.start > section.end {
self.start = 0;
self.end = 0;
} else {
self.start = section.start;
self.end = section.end;
}
}
#[inline]
pub const fn try_as_full_array(&self) -> Option<&[T; N]> {
if self.section_is_full_array() {
Some(&self.array)
} else {
None
}
}
#[inline]
pub fn try_as_full_array_mut(&mut self) -> Option<&mut [T; N]> {
self.section_is_full_array().then_some(&mut self.array)
}
#[inline]
pub const fn as_full_array(&self) -> &[T; N] {
&self.array
}
#[inline]
pub fn as_full_array_mut(&mut self) -> &mut [T; N] {
&mut self.array
}
#[inline]
pub const fn split_at_section(&self) -> (&[T], &[T], &[T]) {
let (head, rest) = self.array.split_at(self.start);
let (section, tail) = rest.split_at(self.end - self.start);
(head, section, tail)
}
#[inline]
pub fn split_at_section_mut(&mut self) -> (&mut [T], &mut [T], &mut [T]) {
let (head, rest) = self.array.split_at_mut(self.start);
let (section, tail) = rest.split_at_mut(self.end - self.start);
(head, section, tail)
}
#[inline]
pub fn into_full_array(self) -> [T; N] {
self.array
}
#[inline]
pub const fn as_slice(&self) -> &[T] {
self.split_at_section().1
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut [T] {
self.split_at_section_mut().1
}
#[inline]
pub const fn len(&self) -> usize {
self.as_slice().len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.as_slice().is_empty()
}
#[inline]
pub const fn section_is_full_array(&self) -> bool {
self.len() == N
}
#[inline]
pub fn iter(&self) -> ArraySectionIter<'_, T> {
ArraySectionIter::new(self.as_slice().iter())
}
#[inline]
pub fn iter_mut(&mut self) -> ArraySectionIterMut<'_, T> {
ArraySectionIterMut::new(self.as_slice_mut().iter_mut())
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
pub fn into_vec(self) -> Vec<T> {
self.into_iter().collect()
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
pub fn into_boxed_slice(self) -> Box<[T]> {
self.into_vec().into_boxed_slice()
}
}
impl<T: Clone, const N: usize> ArraySection<T, N> {
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
pub fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
#[cfg(any(feature = "alloc", feature = "std"))]
#[inline]
pub fn to_boxed_slice(&self) -> Box<[T]> {
self.as_slice().into()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T: Clone, const N: usize> From<ArraySection<T, N>> for Vec<T> {
#[inline]
fn from(value: ArraySection<T, N>) -> Vec<T> {
value.as_slice().into()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T: Clone, const N: usize> From<ArraySection<T, N>> for Box<[T]> {
#[inline]
fn from(value: ArraySection<T, N>) -> Box<[T]> {
value.as_slice().into()
}
}
impl<T: Copy, const N: usize> ArraySection<T, N> {
#[inline]
pub const fn into_full_array_const(self) -> [T; N] {
self.array
}
}
#[derive(Debug)]
pub struct TryFromArraySectionError<T, const N: usize> {
section: ArraySection<T, N>,
#[cfg(feature = "std")]
backtrace: Backtrace,
}
impl<T, const N: usize> TryFromArraySectionError<T, N> {
#[inline]
pub fn array_section(self) -> ArraySection<T, N> {
self.section
}
#[inline]
pub(crate) fn new(section: ArraySection<T, N>) -> Self {
Self {
section,
#[cfg(feature = "std")]
backtrace: Backtrace::capture(),
}
}
#[cfg(feature = "std")]
#[inline]
pub fn backtrace(&self) -> &Backtrace {
&self.backtrace
}
}
impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "the array was not fully populated")
}
}
impl<T: core::fmt::Debug, const N: usize> core::error::Error for TryFromArraySectionError<T, N> {}
impl<T, const N: usize> From<TryFromArraySectionError<T, N>> for ArraySection<T, N> {
#[inline]
fn from(value: TryFromArraySectionError<T, N>) -> Self {
value.section
}
}
impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
type Error = TryFromArraySectionError<T, N>;
#[inline]
fn try_from(value: ArraySection<T, N>) -> Result<Self, Self::Error> {
if value.section_is_full_array() {
Ok(value.array)
} else {
Err(TryFromArraySectionError::new(value))
}
}
}
impl<const N: usize, T> From<[T; N]> for ArraySection<T, N> {
#[inline]
fn from(value: [T; N]) -> Self {
Self {
start: 0,
end: N,
array: value,
}
}
}
impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<const N: usize, T, I: SliceIndex<[T]>> Index<I> for ArraySection<T, N> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
self.as_slice().index(index)
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<T, N>> for ArraySection<U, M>
where
[U]: PartialEq<[T]>,
{
#[inline]
fn eq(&self, other: &ArraySection<T, N>) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<const N: usize, T, U> PartialEq<[U]> for ArraySection<T, N>
where
U: PartialEq<T>,
{
#[inline]
fn eq(&self, other: &[U]) -> bool {
other == self.as_slice()
}
}
impl<const N: usize, T, U> PartialEq<ArraySection<T, N>> for [U]
where
U: PartialEq<T>,
{
#[inline]
fn eq(&self, other: &ArraySection<T, N>) -> bool {
self == other.as_slice()
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<[T; N]> for ArraySection<U, M>
where
[U]: PartialEq<[T]>,
{
#[inline]
fn eq(&self, other: &[T; N]) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<U, M>> for [T; N]
where
[T]: PartialEq<[U]>,
{
#[inline]
fn eq(&self, other: &ArraySection<U, M>) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
type IntoIter = ArraySectionIntoIter<T, N>;
type Item = <ArraySectionIntoIter<T, N> as Iterator>::Item;
#[inline]
fn into_iter(self) -> Self::IntoIter {
let start = self.start;
let len = self.len();
ArraySectionIntoIter::new(self.array.into_iter().skip(start).take(len))
}
}
impl<'a, const N: usize, T> IntoIterator for &'a ArraySection<T, N> {
type IntoIter = ArraySectionIter<'a, T>;
type Item = <ArraySectionIter<'a, T> as Iterator>::Item;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ArraySectionIter::new(self.as_slice().iter())
}
}
impl<'a, const N: usize, T> IntoIterator for &'a mut ArraySection<T, N> {
type IntoIter = ArraySectionIter<'a, T>;
type Item = <ArraySectionIter<'a, T> as Iterator>::Item;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ArraySectionIter::new(self.as_slice().iter())
}
}
pub use array_section_iter_mut::ArraySectionIterMut;
mod array_section_iter_mut {
use super::FusedIterator;
#[derive(Debug)]
pub struct ArraySectionIterMut<'a, T>(core::slice::IterMut<'a, T>);
impl<'a, T> ArraySectionIterMut<'a, T> {
#[inline]
pub(crate) const fn new(iter: core::slice::IterMut<'a, T>) -> Self {
Self(iter)
}
}
impl<'a, T> Iterator for ArraySectionIterMut<'a, T> {
type Item = &'a mut T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
#[inline]
fn last(self) -> Option<Self::Item> {
self.0.last()
}
#[inline]
fn count(self) -> usize {
self.0.count()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a, T> DoubleEndedIterator for ArraySectionIterMut<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
impl<'a, T> ExactSizeIterator for ArraySectionIterMut<'a, T> {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
}
impl<'a, T> FusedIterator for ArraySectionIterMut<'a, T> {}
}
pub use array_section_iter::ArraySectionIter;
mod array_section_iter {
use super::FusedIterator;
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ArraySectionIter<'a, T>(core::slice::Iter<'a, T>);
impl<'a, T> ArraySectionIter<'a, T> {
pub(crate) const fn new(iter: core::slice::Iter<'a, T>) -> Self {
Self(iter)
}
}
impl<'a, T> Iterator for ArraySectionIter<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
#[inline]
fn last(self) -> Option<Self::Item> {
self.0.last()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth(n)
}
#[inline]
fn count(self) -> usize {
self.0.count()
}
}
impl<'a, T> DoubleEndedIterator for ArraySectionIter<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
impl<'a, T> ExactSizeIterator for ArraySectionIter<'a, T> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<'a, T> FusedIterator for ArraySectionIter<'a, T> {}
}
pub use array_section_into_iter::ArraySectionIntoIter;
mod array_section_into_iter {
use super::FusedIterator;
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ArraySectionIntoIter<T, const N: usize>(
core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
);
impl<const N: usize, T> ArraySectionIntoIter<T, N> {
pub(crate) const fn new(
iter: core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
) -> Self {
Self(iter)
}
}
impl<const N: usize, T> Iterator for ArraySectionIntoIter<T, N> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.0.len();
(l, Some(l))
}
#[inline]
fn nth(&mut self, index: usize) -> Option<Self::Item> {
self.0.nth(index)
}
#[inline]
fn last(self) -> Option<T> {
self.0.last()
}
#[inline]
fn count(self) -> usize {
self.0.count()
}
}
impl<const N: usize, T> FusedIterator for ArraySectionIntoIter<T, N> {}
impl<const N: usize, T> ExactSizeIterator for ArraySectionIntoIter<T, N> {}
impl<const N: usize, T> DoubleEndedIterator for ArraySectionIntoIter<T, N> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.0.nth_back(n)
}
}
}