#![no_std]
macro_rules! if_feature {
($s:literal, $($i:item)*) => ($(
#[cfg(feature = $s)] $i
)*)
}
if_feature!("std", extern crate std; use std::hash::{Hash, Hasher};);
if_feature!(
"serde",
use std::{convert::TryInto, marker::PhantomData, fmt, vec::Vec};
use serde::{
de::{Deserialize, Deserializer, Error, SeqAccess, Visitor},
ser::{Serialize, Serializer, SerializeSeq},
};
);
pub type UnorderedPair<T> = UnorderedNTuple<T, 2>;
impl<T> From<(T, T)> for UnorderedPair<T> {
fn from(tuple: (T, T)) -> Self {
Self([tuple.0, tuple.1])
}
}
impl<T> From<UnorderedPair<T>> for (T, T) {
fn from(pair: UnorderedPair<T>) -> (T, T) {
let [first, second] = pair.0;
(first, second)
}
}
#[derive(Copy, Clone, Debug, Eq)]
pub struct UnorderedNTuple<T, const N: usize>(pub [T; N]);
impl<T, const N: usize> From<[T; N]> for UnorderedNTuple<T, N> {
fn from(arg: [T; N]) -> Self {
Self(arg)
}
}
impl<T, const N: usize> From<UnorderedNTuple<T, N>> for [T; N] {
fn from(arg: UnorderedNTuple<T, N>) -> Self {
arg.0
}
}
impl<T, const N: usize> PartialEq for UnorderedNTuple<T, N>
where
T: PartialEq,
{
fn eq(&self, other: &UnorderedNTuple<T, N>) -> bool {
let mut used_indices = [false; N];
for element in self.0.iter() {
let mut found = false;
for (index, other_element) in other.0.iter().enumerate() {
if used_indices[index] {
continue;
}
if element == other_element {
used_indices[index] = true;
found = true;
break;
}
}
if !found {
return false;
}
}
true
}
}
if_feature!(
"std",
impl<T, const N: usize> Hash for UnorderedNTuple<T, N>
where
T: Hash + Ord + Clone,
{
fn hash<H: Hasher>(&self, state: &mut H) {
let mut sorted = self.0.clone();
sorted.sort();
Hash::hash_slice(&sorted, state);
}
}
);
if_feature!(
"serde",
impl<T: Serialize, const N: usize> Serialize for UnorderedNTuple<T, N> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(N))?;
for item in self.0.iter() {
seq.serialize_element(item)?;
}
seq.end()
}
}
struct UnorderedNTupleVisitor<T, const N: usize> {
_phantom: PhantomData<fn() -> [T; N]>,
}
impl<T, const N: usize> UnorderedNTupleVisitor<T, N> {
fn new() -> Self {
Self {
_phantom: PhantomData,
}
}
}
impl<'de, T, const N: usize> Visitor<'de> for UnorderedNTupleVisitor<T, N>
where
T: Deserialize<'de>,
{
type Value = UnorderedNTuple<T, N>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Expecting a sequence with N homogenous elements of type T")
}
fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
where
S: SeqAccess<'de>,
{
if access.size_hint() != Some(N) {
return Err(S::Error::custom("Wrong number of elements"));
}
let mut data: Vec<T> = Vec::new();
for _ in 0..N {
data.push(access.next_element()?.unwrap())
}
Ok(UnorderedNTuple(
data.try_into().unwrap_or_else(|_| unreachable!()),
))
}
}
impl<'de, T: Deserialize<'de>, const N: usize> Deserialize<'de> for UnorderedNTuple<T, N> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(UnorderedNTupleVisitor::<T, N>::new())
}
}
);