#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(
absolute_paths_not_starting_with_crate,
redundant_imports,
redundant_lifetimes,
future_incompatible,
deprecated_in_future,
missing_copy_implementations,
missing_debug_implementations,
missing_docs,
unnameable_types,
unreachable_pub
)]
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
#[cfg(feature = "serde")]
extern crate serde;
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
extern crate alloc;
mod iter;
pub mod proxy;
mod transmute;
pub use crate::iter::*;
use crate::proxy::{Proxy, ProxyWrapper};
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crate::tuple::*;
mod tuple {
#[allow(unreachable_pub)]
pub type Tuple<T, const N: usize> = <[T; N] as IntoTuple>::Tuple;
#[allow(unnameable_types)]
pub trait IntoTuple: Sized {
type Tuple: From<Self>;
}
}
pub type UOrd2<T> = UOrd<T, 2>;
pub type UOrd3<T> = UOrd<T, 3>;
pub type UOrd4<T> = UOrd<T, 4>;
pub type UOrd5<T> = UOrd<T, 5>;
pub type UOrd6<T> = UOrd<T, 6>;
#[repr(transparent)]
pub struct UOrd<T, const N: usize> {
values: [T; N]
}
impl<T, const N: usize> UOrd<T, N> where T: Ord {
pub fn new(mut values: [T; N]) -> Self {
values.sort_unstable();
UOrd { values }
}
pub fn contains<Q>(&self, x: &Q) -> bool
where T: Borrow<Q>, Q: Eq + ?Sized {
self.test_any(|value| value.borrow() == x)
}
pub fn replace<Q>(&self, from: &Q, to: &T) -> Self
where T: Borrow<Q> + Clone, Q: Eq + ?Sized {
self.map_each_ref(|value| {
if value.borrow() == from {
to.clone()
} else {
value.clone()
}
})
}
pub fn map<U>(self, f: impl FnMut(T) -> U) -> UOrd<U, N> where U: Ord {
UOrd::new(self.into_array().map(f))
}
pub fn map_each_ref<U>(&self, f: impl FnMut(&T) -> U) -> UOrd<U, N> where U: Ord {
UOrd::new(self.as_ref_array().map(f))
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn try_map_opt<U>(self, f: impl FnMut(T) -> Option<U>) -> Option<UOrd<U, N>> where U: Ord {
self.into_array().into_iter().map(f).collect::<Option<Vec<U>>>()
.map(|list| <[U; N]>::try_from(list).unwrap_or_else(|_| unreachable!()))
.map(UOrd::new)
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn try_map_res<U, E>(self, f: impl FnMut(T) -> Result<U, E>) -> Result<UOrd<U, N>, E> where U: Ord {
self.into_array().into_iter().map(f).collect::<Result<Vec<U>, E>>()
.map(|list| <[U; N]>::try_from(list).unwrap_or_else(|_| unreachable!()))
.map(UOrd::new)
}
pub fn convert<U>(self) -> UOrd<U, N>
where T: Into<U>, U: Ord {
self.map(T::into)
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn try_convert<U>(self) -> Result<UOrd<U, N>, T::Error>
where T: TryInto<U>, U: Ord {
self.try_map_res(T::try_into)
}
pub fn test_all(&self, f: impl FnMut(&T) -> bool) -> bool {
self.iter().all(f)
}
pub fn test_any(&self, f: impl FnMut(&T) -> bool) -> bool {
self.iter().any(f)
}
pub fn make_proxied<P: Proxy<T>>(self) -> UOrdProxied<T, N, P> {
UOrdProxied::new_proxied(self.into_array())
}
}
impl<T, const N: usize> UOrd<T, N> {
#[doc(alias = "first")]
pub const fn min(&self) -> &T {
self.values.first().expect("uord length must not be 0")
}
#[doc(alias = "last")]
pub const fn max(&self) -> &T {
self.values.last().expect("uord length must not be 0")
}
pub fn each_ref(&self) -> UOrd<&T, N> {
UOrd { values: self.as_ref_array() }
}
pub fn as_ref_array(&self) -> [&T; N] {
self.values.each_ref()
}
#[inline]
pub const fn as_array(&self) -> &[T; N] {
&self.values
}
pub const fn into_array(self) -> [T; N] {
unsafe { crate::transmute::transmute::<Self, [T; N]>(self) }
}
pub fn into_tuple(self) -> Tuple<T, N> where [T; N]: IntoTuple {
<Tuple<T, N>>::from(self.into_array())
}
#[inline]
pub fn iter(&self) -> UOrdIter<'_, T, N> {
self.into_iter()
}
}
pub type UOrdProxied2<T, P> = UOrd2<ProxyWrapper<T, P>>;
pub type UOrdProxied3<T, P> = UOrd3<ProxyWrapper<T, P>>;
pub type UOrdProxied4<T, P> = UOrd4<ProxyWrapper<T, P>>;
pub type UOrdProxied5<T, P> = UOrd5<ProxyWrapper<T, P>>;
pub type UOrdProxied6<T, P> = UOrd6<ProxyWrapper<T, P>>;
pub type UOrdProxied<T, const N: usize, P> = UOrd<ProxyWrapper<T, P>, N>;
impl<T, const N: usize, P> UOrdProxied<T, N, P> where P: Proxy<T> {
pub fn new_proxied(values: [T; N]) -> Self {
UOrd::new(ProxyWrapper::wrap_array(values))
}
pub fn contains_proxied<Q>(&self, x: &Q) -> bool
where T: Borrow<Q>, Q: ?Sized, for<'q> P: Proxy<&'q Q> {
self.test_any_proxied(|value| P::wrap(value.borrow()) == P::wrap(x))
}
pub fn replace_proxied<Q>(&self, from: &Q, to: &T) -> Self
where T: Borrow<Q> + Clone, Q: ?Sized, for<'q> P: Proxy<&'q Q> {
self.map_each_ref_proxied(|value| {
if P::wrap(value.borrow()) == P::wrap(from) {
to.clone()
} else {
value.clone()
}
})
}
pub const fn min_proxied(&self) -> &T {
ProxyWrapper::peel_ref(self.min())
}
pub const fn max_proxied(&self) -> &T {
ProxyWrapper::peel_ref(self.max())
}
pub fn each_ref_proxied(&self) -> UOrd<&T, N> where T: Ord {
UOrd::new(self.as_ref_array_proxied())
}
pub fn as_ref_array_proxied(&self) -> [&T; N] {
self.values.each_ref().map(ProxyWrapper::peel_ref)
}
pub const fn as_array_proxied(&self) -> &[T; N] {
ProxyWrapper::peel_array_ref(self.as_array())
}
pub const fn into_array_proxied(self) -> [T; N] {
ProxyWrapper::peel_array(self.into_array())
}
pub fn into_tuple_proxied(self) -> Tuple<T, N> where [T; N]: IntoTuple {
<Tuple<T, N>>::from(self.into_array_proxied())
}
pub fn map_proxied<U, R>(self, f: impl FnMut(T) -> U) -> UOrdProxied<U, N, R> where R: Proxy<U> {
UOrdProxied::new_proxied(self.into_array_proxied().map(f))
}
pub fn map_each_ref_proxied<U, R>(&self, f: impl FnMut(&T) -> U) -> UOrdProxied<U, N, R> where R: Proxy<U> {
UOrdProxied::new_proxied(self.as_ref_array_proxied().map(f))
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn try_map_proxied_opt<U, R>(self, mut f: impl FnMut(T) -> Option<U>) -> Option<UOrdProxied<U, N, R>> where R: Proxy<U> {
self.try_map_opt(|value| f(ProxyWrapper::into_inner(value)).map(ProxyWrapper::new))
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn try_map_proxied_res<U, R, E>(self, mut f: impl FnMut(T) -> Result<U, E>) -> Result<UOrdProxied<U, N, R>, E> where R: Proxy<U> {
self.try_map_res(|value| f(ProxyWrapper::into_inner(value)).map(ProxyWrapper::new))
}
pub fn convert_proxied<U, R>(self) -> UOrdProxied<U, N, R>
where T: Into<U>, R: Proxy<U> {
self.map_proxied(T::into)
}
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[cfg(feature = "alloc")]
pub fn try_convert_proxied<U, R>(self) -> Result<UOrdProxied<U, N, R>, T::Error>
where T: TryInto<U>, R: Proxy<U> {
self.try_map_proxied_res(T::try_into)
}
pub fn test_all_proxied(&self, f: impl FnMut(&T) -> bool) -> bool {
self.iter_proxied().all(f)
}
pub fn test_any_proxied(&self, f: impl FnMut(&T) -> bool) -> bool {
self.iter_proxied().any(f)
}
pub fn make_unproxied(self) -> UOrd<T, N> where T: Ord {
UOrd::new(self.into_array_proxied())
}
#[inline]
pub fn iter_proxied(&self) -> UOrdProxiedIter<'_, T, N, P> {
UOrdProxiedIter::new(self.as_array())
}
#[inline]
pub fn into_iter_proxied(self) -> UOrdProxiedIntoIter<T, N, P> {
UOrdProxiedIntoIter::new(self.into_array())
}
}
impl<T> UOrd2<T> where T: Ord {
pub fn is_distinct(&self) -> bool {
let [min, max] = self.as_array();
min != max
}
pub fn other<Q>(&self, x: &Q) -> Option<&T>
where T: Borrow<Q>, Q: Eq + ?Sized {
let [min, max] = self.as_array();
Option::or(
if max.borrow() == x { Some(min) } else { None },
if min.borrow() == x { Some(max) } else { None }
)
}
pub fn other_distinct<Q>(&self, x: &Q) -> Option<&T>
where T: Borrow<Q>, Q: Eq + ?Sized {
let [min, max] = self.as_array();
Option::xor(
if max.borrow() == x { Some(min) } else { None },
if min.borrow() == x { Some(max) } else { None }
)
}
}
impl<T, P> UOrdProxied2<T, P> where P: Proxy<T> {
pub fn other_proxied<Q>(&self, x: &Q) -> Option<&T>
where T: Borrow<Q>, Q: ?Sized, for<'q> P: Proxy<&'q Q> {
let [min, max] = self.as_array_proxied();
Option::or(
if P::wrap(max.borrow()) == P::wrap(x) { Some(min) } else { None },
if P::wrap(min.borrow()) == P::wrap(x) { Some(max) } else { None }
)
}
pub fn other_distinct_proxied<Q>(&self, x: &Q) -> Option<&T>
where T: Borrow<Q>, Q: ?Sized, for<'q> P: Proxy<&'q Q> {
let [min, max] = self.as_array_proxied();
Option::xor(
if P::wrap(max.borrow()) == P::wrap(x) { Some(min) } else { None },
if P::wrap(min.borrow()) == P::wrap(x) { Some(max) } else { None }
)
}
}
impl<T: fmt::Display, const N: usize> fmt::Display for UOrd<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_list();
for value in self.values.iter() {
d.entry(&format_args!("{value}"));
};
d.finish()
}
}
impl<T: fmt::Debug, const N: usize> fmt::Debug for UOrd<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_tuple("UOrd");
for value in self.values.iter() {
d.field(&value);
};
d.finish()
}
}
impl<T, const N: usize> Copy for UOrd<T, N> where T: Copy {}
impl<T, const N: usize> Clone for UOrd<T, N> where T: Clone {
fn clone(&self) -> Self {
UOrd { values: self.values.clone() }
}
}
impl<T, const N: usize> PartialEq for UOrd<T, N> where T: Ord {
fn eq(&self, other: &Self) -> bool {
self.as_array() == other.as_array()
}
}
impl<T, const N: usize> Eq for UOrd<T, N> where T: Ord {}
impl<T, const N: usize> PartialOrd for UOrd<T, N> where T: Ord {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Self::cmp(self, other))
}
}
impl<T, const N: usize> Ord for UOrd<T, N> where T: Ord {
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(self.as_array(), other.as_array())
}
}
impl<T, const N: usize> Hash for UOrd<T, N> where T: Hash {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_array().hash(state);
}
}
impl<T, const N: usize> From<[T; N]> for UOrd<T, N> where T: Ord {
fn from(value: [T; N]) -> Self {
UOrd::new(value)
}
}
impl<T, const N: usize> From<UOrd<T, N>> for [T; N] {
fn from(value: UOrd<T, N>) -> Self {
value.into_array()
}
}
macro_rules! impl_uord_tuple_conversion {
($T:ident, $N:literal, $Tuple:ty) => {
impl<$T> IntoTuple for [$T; $N] {
type Tuple = $Tuple;
}
impl<$T> From<$Tuple> for UOrd<$T, $N> where T: Ord {
#[inline]
fn from(value: $Tuple) -> UOrd<$T, $N> {
UOrd::new(<[$T; $N]>::from(value))
}
}
impl<$T> From<UOrd<$T, $N>> for $Tuple {
#[inline]
fn from(value: UOrd<$T, $N>) -> $Tuple {
<$Tuple>::from(value.into_array())
}
}
};
}
impl_uord_tuple_conversion!(T, 1, (T,));
impl_uord_tuple_conversion!(T, 2, (T, T));
impl_uord_tuple_conversion!(T, 3, (T, T, T));
impl_uord_tuple_conversion!(T, 4, (T, T, T, T));
impl_uord_tuple_conversion!(T, 5, (T, T, T, T, T));
impl_uord_tuple_conversion!(T, 6, (T, T, T, T, T, T));
impl_uord_tuple_conversion!(T, 7, (T, T, T, T, T, T, T));
impl_uord_tuple_conversion!(T, 8, (T, T, T, T, T, T, T, T));
impl_uord_tuple_conversion!(T, 9, (T, T, T, T, T, T, T, T, T));
impl_uord_tuple_conversion!(T, 10, (T, T, T, T, T, T, T, T, T, T));
impl_uord_tuple_conversion!(T, 11, (T, T, T, T, T, T, T, T, T, T, T));
impl_uord_tuple_conversion!(T, 12, (T, T, T, T, T, T, T, T, T, T, T, T));
impl<'a, T, const N: usize> IntoIterator for &'a UOrd<T, N> {
type Item = &'a T;
type IntoIter = UOrdIter<'a, T, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
UOrdIter::new(self.as_array())
}
}
impl<T, const N: usize> IntoIterator for UOrd<T, N> {
type Item = T;
type IntoIter = UOrdIntoIter<T, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
UOrdIntoIter::new(self.into_array())
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
#[cfg(feature = "serde")]
impl<T, const N: usize> serde::Serialize for UOrd<T, N>
where T: serde::Serialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
<[T; N] as serde_big_array::BigArray<T>>::serialize(self.as_array(), serializer)
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
#[cfg(feature = "serde")]
impl<'de, T, const N: usize> serde::Deserialize<'de> for UOrd<T, N>
where T: serde::Deserialize<'de> + Ord {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de> {
<[T; N] as serde_big_array::BigArray<T>>::deserialize(deserializer).map(UOrd::new)
}
}