use alloc::vec;
use alloc::vec::Vec;
use core::marker::ConstParamTy_;
use core::marker::Destruct;
use core::marker::Freeze;
use crate::bendn_sort;
use crate::const_helpers as ch;
use crate::spec::try_fn_once;
use crate::sure_eq::SureEq;
pub(crate) const LENGTH<T: ConstParamTy_ + 'static, const SET: &'static [T]>: usize =
const { SET.len() };
pub(crate) const CARTESIAN_LENGTH<
T: ConstParamTy_ + 'static,
U: ConstParamTy_ + 'static,
const A: &'static [T],
const B: &'static [U],
>: usize = const { A.len() * B.len() };
#[expect(clippy::ok_expect)]
pub const SORT<
T: const Ord + ConstParamTy_ + Copy + const Destruct + Freeze + 'static,
const SET: &'static [T]
>: &[T] = const {
let arr: [T; LENGTH::<T, SET>] = SET.try_into().ok().expect("this is infallible");
&ch::sort(arr)
};
pub const NORMALIZE<
T: SureEq + const Ord + Copy + const Destruct + 'static,
const SET: &'static [T],
>: &[T] = const {
normalize::<T, {LENGTH::<T, SET>}>(SET)
};
pub const UNION<T: ConstParamTy_ + Copy + Freeze + 'static , const SETS: &'static [&'static [T]]>:
&[T] = const {
union_(SETS).const_make_global()
};
pub const INTERSECTION<
T: SureEq + Copy + const Destruct + 'static ,
const SETS: &'static [&'static [T]],
>: &[T] = const {
intersection(SETS).const_make_global()
};
const fn deduped<T: SureEq + Copy>(slice: &[T]) -> Vec<T> {
let [first, ..] = slice else { return vec![] };
let mut deduped: Vec<T> = vec![*first];
let mut i = 1; while i < slice.len() {
let (previous, current) = (slice[i - 1], slice[i]);
if previous != current {
deduped.push(current);
}
i += 1;
}
deduped
}
const fn union_<T: Copy>(sets: &[&[T]]) -> Vec<T> {
let mut union_: Vec<T> = vec![];
let mut i: usize = 0;
while i < sets.len() {
let mut j: usize = 0;
while j < sets[i].len() {
union_.push(sets[i][j]);
j += 1;
}
i += 1;
}
union_
}
const fn intersection<T: SureEq + Copy + [const] Destruct>(sets: &[&[T]]) -> Vec<T> {
let [first_set, ..] = sets else {
return vec![];
};
let mut intersection: Vec<T> = ch::slice_to_vec(first_set);
let mut i: usize = 1; while i < sets.len() {
ch::vec_reduce_to_intersection_with(&mut intersection, sets[i]);
i += 1;
}
intersection
}
#[expect(clippy::ok_expect)]
const fn normalize<
T: SureEq + [const] Ord + Copy + [const] Destruct + 'static,
const LEN: usize,
>(
slice: &'static [T],
) -> &'static [T] {
let slice: &[T] = match try_fn_once::<&[T], Vec<T>, &[u8], Vec<u8>>(slice, normalize_u8) {
Ok(normalized) => return normalized.const_make_global(),
Err(slice) => slice,
};
let slice: &[T] = match try_fn_once::<&[T], Vec<T>, &[u16], Vec<u16>>(slice, normalize_u16) {
Ok(normalized) => return normalized.const_make_global(),
Err(slice) => slice,
};
let slice: &[T] = match try_fn_once::<&[T], &[T], &[u32], &[u32]>(slice, normalize_u32) {
Ok(normalized) => return deduped(normalized).const_make_global(),
Err(slice) => slice,
};
let arr: [T; LEN] = slice.try_into().ok().expect("this is infallible");
let sorted = ch::sort(arr);
deduped(&sorted).const_make_global()
}
macro_rules! define_normalize_narrow_uint {
($ty:ty, $name:ident) => {
#[allow(clippy::large_stack_arrays)]
const fn $name(slice: &[$ty]) -> Vec<$ty> {
const ELEMENT_COUNT: usize = (<$ty>::MAX as usize) + 1;
let mut element_bitset: [bool; ELEMENT_COUNT] = [false; ELEMENT_COUNT];
let mut i: usize = 0;
while i < slice.len() {
element_bitset[slice[i] as usize] = true;
i += 1;
}
let mut normalized: Vec<$ty> = Vec::with_capacity(ELEMENT_COUNT);
let mut i: $ty = 0;
loop {
if element_bitset[i as usize] {
normalized.push(i);
}
if i == <$ty>::MAX {
break;
}
i += 1;
}
normalized
}
};
}
define_normalize_narrow_uint!(u8, normalize_u8);
define_normalize_narrow_uint!(u16, normalize_u16);
#[expect(clippy::trivially_copy_pass_by_ref)]
const fn normalize_u32(slice: &'static [u32]) -> &'static [u32] {
const fn u32_to_usize(v: &u32) -> usize {
usize::try_from(*v).ok().unwrap()
}
bendn_sort::radixsort(slice, u32_to_usize)
}