use crate::error::TooLongSliceForPermutation;
use crate::util::AlwaysEq;
use crate::Permutation;
#[derive(Ord, PartialOrd, Eq, PartialEq)]
enum SortHelper<'a, T> {
ActualValue(AlwaysEq<usize>, &'a T),
Lengthening(usize),
}
impl<'a, T> SortHelper<'a, T> {
fn index(&self) -> usize {
match *self {
Self::ActualValue(i, _) => i.0,
Self::Lengthening(i) => i,
}
}
}
pub trait SortArray<const N: usize> {
#[allow(missing_docs)] fn sort<T: Ord>(arr: &mut [T; N]);
}
pub trait SortSlice {
#[allow(missing_docs)] fn sort<T: Ord>(sl: &mut [T]);
}
pub struct CoreSortUnstable;
impl<const N: usize> SortArray<N> for CoreSortUnstable {
fn sort<T: Ord>(arr: &mut [T; N]) {
arr.sort_unstable();
}
}
impl SortSlice for CoreSortUnstable {
fn sort<T: Ord>(sl: &mut [T]) {
sl.sort_unstable();
}
}
#[cfg(feature = "std")]
pub struct StdSort;
#[cfg(feature = "std")]
impl<const N: usize> SortArray<N> for StdSort {
fn sort<T: Ord>(arr: &mut [T; N]) {
arr.sort();
}
}
#[cfg(feature = "std")]
impl SortSlice for StdSort {
fn sort<T: Ord>(sl: &mut [T]) {
sl.sort();
}
}
impl<const N: usize> Permutation<N> {
pub fn from_custom_sort<T: Ord, S: SortArray<N>>(arr: &[T; N]) -> Self {
let mut to_sort: [_; N] =
core::array::from_fn(|i| SortHelper::ActualValue(AlwaysEq(i), &arr[i]));
S::sort(&mut to_sort);
Self {
arr_repr: to_sort.map(|s| s.index()),
}
}
#[inline]
pub fn from_sort_unstable<T: Ord>(arr: &[T; N]) -> Self {
Self::from_custom_sort::<T, CoreSortUnstable>(arr)
}
#[cfg(feature = "std")]
#[inline]
pub fn from_sort<T: Ord>(arr: &[T; N]) -> Self {
Self::from_custom_sort::<T, StdSort>(arr)
}
pub fn from_custom_sort_slice<T: Ord, S: SortSlice>(
sl: &[T],
) -> Result<Self, TooLongSliceForPermutation> {
if sl.len() > N {
return Err(TooLongSliceForPermutation {
length: sl.len(),
max: N,
});
}
let mut arr: [_; N] = core::array::from_fn(|i| match sl.get(i) {
Some(x) => SortHelper::ActualValue(AlwaysEq(i), x),
None => SortHelper::Lengthening(i),
});
S::sort(&mut arr[..]);
Ok(Self {
arr_repr: arr.map(|s| s.index()),
})
}
#[inline]
pub fn from_sort_unstable_slice<T: Ord>(sl: &[T]) -> Result<Self, TooLongSliceForPermutation> {
Self::from_custom_sort_slice::<T, CoreSortUnstable>(sl)
}
#[cfg(feature = "std")]
#[inline]
pub fn from_sort_slice<T: Ord>(sl: &[T]) -> Result<Self, TooLongSliceForPermutation> {
Self::from_custom_sort_slice::<T, StdSort>(sl)
}
}