#![cfg_attr(not(test), no_std)]
#![allow(incomplete_features, internal_features)]
#![feature(
const_destruct,
adt_const_params,
generic_const_exprs,
core_intrinsics,
iter_intersperse,
const_trait_impl,
maybe_uninit_array_assume_init,
array_windows,
iter_map_windows
)]
#![warn(
clippy::undocumented_unsafe_blocks,
clippy::missing_const_for_fn,
clippy::missing_safety_doc,
clippy::suboptimal_flops,
unsafe_op_in_unsafe_fn,
clippy::dbg_macro,
clippy::use_self,
missing_docs
)]
use core::{
array::from_fn,
intrinsics::transmute_unchecked,
marker::Destruct,
mem::{MaybeUninit as MU, offset_of},
};
pub mod pervasive;
mod slice;
mod tuple;
#[doc(inline)]
pub use slice::Slice;
pub use tuple::*;
pub mod prelude {
#[doc(inline)]
pub use super::{
Array, ArrayTools, Chunked, CollectArray, Couple, Deconstruct, Flatten, Join, Split, Tuple,
Zip, pervasive::prelude::*, range, slice::Slice, slice::r, splat,
};
#[doc(inline)]
pub use core::array::from_fn;
}
#[repr(C)]
struct Pair<X, Y>(X, Y);
impl<X, Y> Pair<X, Y> {
const fn tuple() -> bool {
(size_of::<(X, Y)>() == size_of::<Self>())
& (offset_of!(Self, 0) == offset_of!((X, Y), 0))
& (offset_of!(Self, 1) == offset_of!((X, Y), 1))
}
const fn into(self) -> (X, Y) {
if Self::tuple() {
unsafe { transmute_unchecked::<Self, (X, Y)>(self) }
} else {
let out = unsafe { (core::ptr::read(&self.0), core::ptr::read(&self.1)) };
core::mem::forget(self);
out
}
}
const unsafe fn splat<T>(x: T) -> (X, Y) {
assert!(core::mem::size_of::<T>() == core::mem::size_of::<Pair<X, Y>>());
unsafe { transmute_unchecked::<_, Self>(x) }.into()
}
}
pub fn splat<T: Clone, const N: usize>(a: T) -> [T; N] {
from_fn(|_| a.clone())
}
pub const fn range<const N: usize>() -> [usize; N] {
let mut out = unsafe { MU::<[MU<usize>; N]>::uninit().assume_init() };
let mut i = 0usize;
while i < out.len() {
out[i] = MU::new(i);
i += 1;
}
unsafe { transmute_unchecked(out) }
}
pub trait CollectArray<T> {
fn carr<const N: usize>(&mut self) -> [T; N];
}
impl<T, I: Iterator<Item = T>> CollectArray<T> for I {
fn carr<const N: usize>(&mut self) -> [T; N] {
from_fn(|_| self.next().unwrap())
}
}
pub const trait Deconstruct<T, const N: usize> {
fn uncons(self) -> (T, [T; N - 1]);
fn unsnoc(self) -> ([T; N - 1], T);
fn init(self) -> [T; N - 1];
fn tail(self) -> [T; N - 1];
fn last(self) -> T
where
[(); N - 1]:;
fn head(self) -> T
where
[(); N - 1]:;
}
impl<T, const N: usize> const Deconstruct<T, N> for [T; N]
where
T: [const] Destruct,
{
#[doc(alias = "pop_front")]
fn uncons(self) -> (T, [T; N - 1]) {
unsafe { Pair::splat(self) }
}
#[doc(alias = "pop")]
fn unsnoc(self) -> ([T; N - 1], T) {
unsafe { Pair::splat(self) }
}
fn tail(self) -> [T; N - 1]
where
T: [const] Destruct,
{
self.uncons().1
}
#[doc(alias = "trunc")]
fn init(self) -> [T; N - 1] {
self.unsnoc().0
}
fn last(self) -> T
where
[(); N - 1]:,
{
self.unsnoc().1
}
fn head(self) -> T
where
[(); N - 1]:,
{
self.uncons().0
}
}
pub const trait Join<T, const N: usize, const O: usize, U> {
fn join(self, with: U) -> [T; N + O];
}
pub const trait Couple<T, const N: usize, const O: usize> {
fn couple(self, with: [T; O]) -> [T; N + O];
}
impl<T, const N: usize, const O: usize> const Couple<T, N, O> for [T; N] {
fn couple(self, with: [T; O]) -> [T; N + O] {
unsafe { transmute_unchecked(Pair(self, with)) }
}
}
impl<T, const N: usize> const Join<T, N, 1, T> for [T; N] {
fn join(self, with: T) -> [T; N + 1] {
self.couple([with])
}
}
impl<T> const Join<T, 1, 1, T> for T {
fn join(self, with: T) -> [T; 2] {
[self, with]
}
}
impl<T, const O: usize> const Join<T, 1, O, [T; O]> for T {
fn join(self, with: [T; O]) -> [T; 1 + O] {
[self].couple(with)
}
}
#[allow(private_bounds)]
pub const trait Chunked<T, const N: usize> {
#[allow(private_bounds)]
fn chunked<const C: usize>(self) -> [[T; C]; N / C]
where
[(); N % C + usize::MAX]:;
}
impl<const N: usize, T> const Chunked<T, N> for [T; N] {
#[allow(private_bounds)]
fn chunked<const C: usize>(self) -> [[T; C]; N / C]
where
[(); N % C + usize::MAX]:,
{
let retval = unsafe { self.as_ptr().cast::<[[T; C]; N / C]>().read() };
core::mem::forget(self);
retval
}
}
pub const trait Flatten<T, const N: usize, const N2: usize> {
fn flatten(self) -> [T; N * N2];
}
impl<T, const N: usize, const M: usize> const Flatten<T, N, M> for [[T; M]; N] {
fn flatten(self) -> [T; N * M] {
unsafe { core::intrinsics::transmute_unchecked(self) }
}
}
pub const trait Split<T, const N: usize> {
fn split<const AT: usize>(self) -> ([T; AT], [T; N - AT]);
fn take<const AT: usize>(self) -> [T; AT]
where
[(); N - AT]:,
T: [const] Destruct;
fn drop<const AT: usize>(self) -> [T; N - AT]
where
T: [const] Destruct;
}
impl<T, const N: usize> const Split<T, N> for [T; N] {
fn split<const AT: usize>(self) -> ([T; AT], [T; N - AT]) {
unsafe { Pair::splat(self) }
}
fn take<const M: usize>(self) -> [T; M]
where
[(); N - M]:,
T: [const] Destruct,
{
self.split::<M>().0
}
fn drop<const M: usize>(self) -> [T; N - M]
where
T: [const] Destruct,
{
self.split::<M>().1
}
}
pub const trait Zip<T, const N: usize> {
fn zip<U>(self, with: [U; N]) -> [(T, U); N];
}
impl<T, const N: usize> const Zip<T, N> for [T; N] {
fn zip<U>(self, with: [U; N]) -> [(T, U); N] {
let mut out = unsafe { MU::<[MU<_>; N]>::uninit().assume_init() };
let mut i = 0usize;
while i < out.len() {
out[i] = MU::new(unsafe { (self.as_ptr().add(i).read(), with.as_ptr().add(i).read()) });
i += 1;
}
core::mem::forget((self, with));
unsafe { transmute_unchecked(out) }
}
}
pub trait ArrayTools<T, const N: usize> {
fn skip<const BY: usize>(self) -> [T; N - BY];
fn step<const STEP: usize>(self) -> [T; 1 + (N - 1) / (STEP)];
fn intersperse(self, with: T) -> [T; (N * 2) - 1]
where
T: Clone;
fn each(self, apply: impl FnMut(T));
fn enumerate(self) -> [(T, usize); N];
fn windowed<const W: usize>(&self) -> [&[T; W]; N - W + 1];
fn inspect(self, f: impl FnMut(&T)) -> Self;
fn rev(self) -> Self;
fn interleave(self, with: [T; N]) -> [T; N * 2];
fn cartesian_product<U: Clone, const M: usize>(self, with: &[U; M]) -> [(T, U); N * M]
where
T: Clone;
fn sort(self) -> Self
where
T: Ord;
fn sum(self) -> T
where
T: core::iter::Sum<T>;
fn product(self) -> T
where
T: core::iter::Product<T>;
}
impl<T, const N: usize> ArrayTools<T, N> for [T; N] {
fn skip<const BY: usize>(self) -> [T; N - BY] {
self.into_iter().skip(BY).carr()
}
fn step<const STEP: usize>(self) -> [T; 1 + (N - 1) / (STEP)] {
self.into_iter().step_by(STEP).carr()
}
fn intersperse(self, with: T) -> [T; (N * 2) - 1]
where
T: Clone,
{
self.into_iter().intersperse(with).carr()
}
fn each(self, apply: impl FnMut(T)) {
self.into_iter().for_each(apply);
}
fn enumerate(self) -> [(T, usize); N] {
let mut n = 0;
self.map(|x| {
let o = n;
n += 1;
(x, o)
})
}
fn windowed<const W: usize>(&self) -> [&[T; W]; N - W + 1] {
self.array_windows().carr()
}
fn inspect(self, f: impl FnMut(&T)) -> Self {
self.iter().for_each(f);
self
}
fn rev(mut self) -> Self {
self.reverse();
self
}
fn interleave(self, with: [T; N]) -> [T; N * 2] {
let mut which = true;
let mut a = self.into_iter();
let mut b = with.into_iter();
from_fn(|_| {
which = !which;
match which {
false => a.next().unwrap(),
true => b.next().unwrap(),
}
})
}
fn cartesian_product<U: Clone, const M: usize>(self, with: &[U; M]) -> [(T, U); N * M]
where
T: Clone,
{
self.map(|a| with.clone().map(move |b| (a.clone(), b)))
.flatten()
}
fn sort(mut self) -> Self
where
T: Ord,
{
<[T]>::sort_unstable(&mut self);
self
}
fn sum(self) -> T
where
T: core::iter::Sum<T>,
{
self.into_iter().sum()
}
fn product(self) -> T
where
T: core::iter::Product<T>,
{
self.into_iter().product()
}
}