use crate::WithContext;
use std::cmp::Ordering;
pub struct OrdContext<T> {
pub compare: fn(&T, &T) -> Ordering,
}
impl<T> Clone for OrdContext<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for OrdContext<T> {}
impl<T> std::fmt::Debug for OrdContext<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OrdContext")
.field("compare", &(self.compare as usize))
.finish()
}
}
impl<T> PartialEq for WithContext<T, OrdContext<T>> {
fn eq(&self, other: &Self) -> bool {
(self.ctx.compare)(&self.inner, &other.inner) == Ordering::Equal
}
}
impl<T> Eq for WithContext<T, OrdContext<T>> {}
impl<T> PartialOrd for WithContext<T, OrdContext<T>> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T> Ord for WithContext<T, OrdContext<T>> {
fn cmp(&self, other: &Self) -> Ordering {
(self.ctx.compare)(&self.inner, &other.inner)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sort_with_custom_ord() {
let ctx = OrdContext {
compare: |a: &i32, b: &i32| b.cmp(a),
};
let mut items: Vec<_> = [3, 1, 4, 1, 5]
.iter()
.map(|&v| WithContext { inner: v, ctx })
.collect();
items.sort();
let values: Vec<i32> = items.into_iter().map(|w| w.inner).collect();
assert_eq!(values, vec![5, 4, 3, 1, 1]);
}
#[test]
fn equality_through_context() {
let ctx = OrdContext {
compare: |a: &(i32, i32), b: &(i32, i32)| a.0.cmp(&b.0),
};
let a = WithContext {
inner: (1, 100),
ctx,
};
let b = WithContext {
inner: (1, 200),
ctx,
};
assert_eq!(a, b);
}
#[test]
fn btreeset_with_custom_ord() {
use std::collections::BTreeSet;
let ctx = OrdContext {
compare: |a: &String, b: &String| a.len().cmp(&b.len()),
};
let mut set = BTreeSet::new();
set.insert(WithContext {
inner: "hello".to_string(),
ctx,
});
set.insert(WithContext {
inner: "hi".to_string(),
ctx,
});
set.insert(WithContext {
inner: "world".to_string(),
ctx,
});
assert_eq!(set.len(), 2);
}
}