1use crate::WithContext;
4use std::cmp::Ordering;
5
6pub struct OrdContext<T> {
26 pub compare: fn(&T, &T) -> Ordering,
28}
29
30impl<T> Clone for OrdContext<T> {
32 fn clone(&self) -> Self {
33 *self
34 }
35}
36impl<T> Copy for OrdContext<T> {}
37impl<T> std::fmt::Debug for OrdContext<T> {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 f.debug_struct("OrdContext")
40 .field("compare", &(self.compare as usize))
41 .finish()
42 }
43}
44
45impl<T> PartialEq for WithContext<T, OrdContext<T>> {
46 fn eq(&self, other: &Self) -> bool {
47 (self.ctx.compare)(&self.inner, &other.inner) == Ordering::Equal
48 }
49}
50
51impl<T> Eq for WithContext<T, OrdContext<T>> {}
52
53impl<T> PartialOrd for WithContext<T, OrdContext<T>> {
54 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
55 Some(self.cmp(other))
56 }
57}
58
59impl<T> Ord for WithContext<T, OrdContext<T>> {
60 fn cmp(&self, other: &Self) -> Ordering {
61 (self.ctx.compare)(&self.inner, &other.inner)
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn sort_with_custom_ord() {
71 let ctx = OrdContext {
72 compare: |a: &i32, b: &i32| b.cmp(a),
73 };
74 let mut items: Vec<_> = [3, 1, 4, 1, 5]
75 .iter()
76 .map(|&v| WithContext { inner: v, ctx })
77 .collect();
78 items.sort();
79 let values: Vec<i32> = items.into_iter().map(|w| w.inner).collect();
80 assert_eq!(values, vec![5, 4, 3, 1, 1]);
81 }
82
83 #[test]
84 fn equality_through_context() {
85 let ctx = OrdContext {
86 compare: |a: &(i32, i32), b: &(i32, i32)| a.0.cmp(&b.0),
87 };
88 let a = WithContext {
89 inner: (1, 100),
90 ctx,
91 };
92 let b = WithContext {
93 inner: (1, 200),
94 ctx,
95 };
96 assert_eq!(a, b);
98 }
99
100 #[test]
101 fn btreeset_with_custom_ord() {
102 use std::collections::BTreeSet;
103
104 let ctx = OrdContext {
105 compare: |a: &String, b: &String| a.len().cmp(&b.len()),
106 };
107
108 let mut set = BTreeSet::new();
109 set.insert(WithContext {
110 inner: "hello".to_string(),
111 ctx,
112 });
113 set.insert(WithContext {
114 inner: "hi".to_string(),
115 ctx,
116 });
117 set.insert(WithContext {
118 inner: "world".to_string(),
119 ctx,
120 }); assert_eq!(set.len(), 2);
124 }
125}