unordered_n_tuple/
lib.rs

1#![no_std]
2
3//! This crate provides a `UnorderedNTuple`, which is a struct that represents unordered tuples of
4//! n homogenous elements.
5//!
6//! ## Crate Features
7//! - `std`: Enables dependence on `std` to allow for more features
8//! - `serde`: Enabls serializing/deserializing the `UnorderedNTuple` struct in serde
9//!
10//! By default, both features are enabled.
11
12macro_rules! if_feature {
13    ($s:literal, $($i:item)*) => ($(
14        #[cfg(feature = $s)] $i
15    )*)
16}
17
18if_feature!("std", extern crate std; use std::hash::{Hash, Hasher};);
19
20if_feature!(
21    "serde",
22    use std::{convert::TryInto, marker::PhantomData, fmt, vec::Vec};
23    use serde::{
24        de::{Deserialize, Deserializer, Error, SeqAccess, Visitor},
25        ser::{Serialize, Serializer, SerializeSeq},
26    };
27);
28
29/// An `UnorderedPair` is a special subtype of `UnorderedNTuple` for only 2 elements. This has been
30/// given its own type for ease of use.
31///
32/// It can also be converted to or from a tuple (similar impls for larger types will come once
33/// generics become stronger).
34pub type UnorderedPair<T> = UnorderedNTuple<T, 2>;
35
36impl<T> From<(T, T)> for UnorderedPair<T> {
37    fn from(tuple: (T, T)) -> Self {
38        Self([tuple.0, tuple.1])
39    }
40}
41impl<T> From<UnorderedPair<T>> for (T, T) {
42    fn from(pair: UnorderedPair<T>) -> (T, T) {
43        let [first, second] = pair.0;
44        (first, second)
45    }
46}
47
48/// A type which represents an unordered tuple of N elements (i.e. an unordered pair if N == 2, and
49/// unordered triplet if N == 3, and so on).
50///
51/// Two `UnorderedNTuple`s are equivalent if their elements are equivalent in any order, for
52/// example:
53/// ```
54/// # use unordered_n_tuple::UnorderedNTuple;
55/// assert_eq!(UnorderedNTuple([0, 3, 5]), UnorderedNTuple([5, 0, 3]));
56/// ```
57#[derive(Copy, Clone, Debug, Eq)]
58pub struct UnorderedNTuple<T, const N: usize>(pub [T; N]);
59
60impl<T, const N: usize> From<[T; N]> for UnorderedNTuple<T, N> {
61    fn from(arg: [T; N]) -> Self {
62        Self(arg)
63    }
64}
65
66impl<T, const N: usize> From<UnorderedNTuple<T, N>> for [T; N] {
67    fn from(arg: UnorderedNTuple<T, N>) -> Self {
68        arg.0
69    }
70}
71
72impl<T, const N: usize> PartialEq for UnorderedNTuple<T, N>
73where
74    T: PartialEq,
75{
76    fn eq(&self, other: &UnorderedNTuple<T, N>) -> bool {
77        let mut used_indices = [false; N];
78        for element in self.0.iter() {
79            let mut found = false;
80            for (index, other_element) in other.0.iter().enumerate() {
81                if used_indices[index] {
82                    continue;
83                }
84                if element == other_element {
85                    used_indices[index] = true;
86                    found = true;
87                    break;
88                }
89            }
90            if !found {
91                return false;
92            }
93        }
94        true
95    }
96}
97
98if_feature!(
99    "std",
100    impl<T, const N: usize> Hash for UnorderedNTuple<T, N>
101    where
102        T: Hash + Ord + Clone,
103    {
104        fn hash<H: Hasher>(&self, state: &mut H) {
105            let mut sorted = self.0.clone();
106            sorted.sort();
107            Hash::hash_slice(&sorted, state);
108        }
109    }
110);
111
112if_feature!(
113    "serde",
114    impl<T: Serialize, const N: usize> Serialize for UnorderedNTuple<T, N> {
115        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
116        where
117            S: Serializer,
118        {
119            let mut seq = serializer.serialize_seq(Some(N))?;
120            for item in self.0.iter() {
121                seq.serialize_element(item)?;
122            }
123            seq.end()
124        }
125    }
126    struct UnorderedNTupleVisitor<T, const N: usize> {
127        _phantom: PhantomData<fn() -> [T; N]>,
128    }
129    impl<T, const N: usize> UnorderedNTupleVisitor<T, N> {
130        fn new() -> Self {
131            Self {
132                _phantom: PhantomData,
133            }
134        }
135    }
136    impl<'de, T, const N: usize> Visitor<'de> for UnorderedNTupleVisitor<T, N>
137    where
138        T: Deserialize<'de>,
139    {
140        type Value = UnorderedNTuple<T, N>;
141
142        fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
143            f.write_str("Expecting a sequence with N homogenous elements of type T")
144        }
145
146        fn visit_seq<S>(self, mut access: S) -> Result<Self::Value, S::Error>
147        where
148            S: SeqAccess<'de>,
149        {
150            if access.size_hint() != Some(N) {
151                return Err(S::Error::custom("Wrong number of elements"));
152            }
153            let mut data: Vec<T> = Vec::new();
154            for _ in 0..N {
155                data.push(access.next_element()?.unwrap())
156            }
157            Ok(UnorderedNTuple(
158                data.try_into().unwrap_or_else(|_| unreachable!()),
159            ))
160        }
161    }
162    impl<'de, T: Deserialize<'de>, const N: usize> Deserialize<'de> for UnorderedNTuple<T, N> {
163        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
164        where
165            D: Deserializer<'de>,
166        {
167            deserializer.deserialize_seq(UnorderedNTupleVisitor::<T, N>::new())
168        }
169    }
170);