amadeus_types/
ord.rs

1use std::{cmp::Ordering, collections::HashMap, hash::BuildHasher};
2
3pub trait AmadeusOrd {
4	fn amadeus_cmp(&self, other: &Self) -> Ordering;
5}
6
7macro_rules! ord {
8	($($t:ty)*) => {$(
9		impl AmadeusOrd for $t {
10			fn amadeus_cmp(&self, other: &Self) -> Ordering {
11				Ord::cmp(self, other)
12			}
13		}
14	)*}
15}
16ord!(bool u8 i8 u16 i16 u32 i32 u64 i64 String);
17
18impl AmadeusOrd for f32 {
19	fn amadeus_cmp(&self, other: &Self) -> Ordering {
20		Ord::cmp(
21			&ordered_float::OrderedFloat(*self),
22			&ordered_float::OrderedFloat(*other),
23		)
24	}
25}
26impl AmadeusOrd for f64 {
27	fn amadeus_cmp(&self, other: &Self) -> Ordering {
28		Ord::cmp(
29			&ordered_float::OrderedFloat(*self),
30			&ordered_float::OrderedFloat(*other),
31		)
32	}
33}
34
35impl<T> AmadeusOrd for &T
36where
37	T: AmadeusOrd + ?Sized,
38{
39	fn amadeus_cmp(&self, other: &Self) -> Ordering {
40		(**self).amadeus_cmp(&**other)
41	}
42}
43
44impl<T> AmadeusOrd for Box<T>
45where
46	T: AmadeusOrd,
47{
48	fn amadeus_cmp(&self, other: &Self) -> Ordering {
49		(**self).amadeus_cmp(&**other)
50	}
51}
52
53/// Sort `None` as larger than any non-`None` value
54impl<T> AmadeusOrd for Option<T>
55where
56	T: AmadeusOrd,
57{
58	fn amadeus_cmp(&self, other: &Self) -> Ordering {
59		match (self, other) {
60			(Some(a), Some(b)) => a.amadeus_cmp(b),
61			(None, None) => Ordering::Equal,
62			(None, Some(_)) => Ordering::Greater,
63			(Some(_), None) => Ordering::Less,
64		}
65	}
66}
67
68impl<T> AmadeusOrd for Vec<T>
69where
70	T: AmadeusOrd,
71{
72	fn amadeus_cmp(&self, other: &Self) -> Ordering {
73		for i in 0..self.len().min(other.len()) {
74			match self[i].amadeus_cmp(&other[i]) {
75				Ordering::Equal => (),
76				res => return res,
77			}
78		}
79		self.len().cmp(&other.len())
80	}
81}
82
83impl<K, V, S> AmadeusOrd for HashMap<K, V, S>
84where
85	K: AmadeusOrd,
86	V: AmadeusOrd,
87	S: BuildHasher,
88{
89	fn amadeus_cmp(&self, other: &Self) -> Ordering {
90		let mut keys: Vec<(&K, &V, bool)> = self
91			.iter()
92			.map(|(k, v)| (k, v, false))
93			.chain(other.iter().map(|(k, v)| (k, v, true)))
94			.collect();
95		keys.sort_by(|(a, _, _), (b, _, _)| a.amadeus_cmp(b));
96		let mut keys = &*keys;
97		while keys.len() >= 2 {
98			let ((a_k, a_v, a_r), (b_k, b_v, b_r)) = (keys[0], keys[1]);
99			if !a_r && b_r {
100				match a_k.amadeus_cmp(b_k) {
101					Ordering::Equal => (),
102					res => return res,
103				}
104				match a_v.amadeus_cmp(b_v) {
105					Ordering::Equal => (),
106					res => return res,
107				}
108				keys = &keys[2..];
109			} else if !a_r {
110				return Ordering::Greater;
111			} else {
112				return Ordering::Less;
113			}
114		}
115		if keys.len() == 1 {
116			if !keys[0].2 {
117				Ordering::Greater
118			} else {
119				Ordering::Less
120			}
121		} else {
122			Ordering::Equal
123		}
124	}
125}
126
127macro_rules! ord {
128	($($i:tt)*) => {$(
129		impl<T> AmadeusOrd for [T; $i]
130		where
131			T: AmadeusOrd
132		{
133			fn amadeus_cmp(&self, other: &Self) -> Ordering {
134				for (a,b) in self.iter().zip(other.iter()) {
135					match a.amadeus_cmp(b) {
136						Ordering::Equal => (),
137						res => return res,
138					}
139				}
140				Ordering::Equal
141			}
142		}
143	)*};
144}
145array!(ord);
146
147macro_rules! ord {
148	($len:tt $($t:ident $i:tt)*) => {
149		impl<$($t,)*> AmadeusOrd for ($($t,)*) where $($t: AmadeusOrd,)* {
150			#[allow(unused_variables)]
151			fn amadeus_cmp(&self, other: &Self) -> Ordering {
152				Ordering::Equal
153					$(.then_with(|| self.$i.amadeus_cmp(&other.$i)))*
154			}
155		}
156	};
157}
158tuple!(ord);