1use std::any::Any;
12use std::any::TypeId;
13use std::cmp::Ordering;
14use std::marker::PhantomData;
15
16pub struct OrdAny<'a> {
18 type_id: TypeId,
19 cmp: unsafe fn(*const (), *const ()) -> Ordering,
20 val: *const (),
21 _marker: PhantomData<&'a dyn Any>,
22}
23
24impl<'a> OrdAny<'a> {
25 #[inline]
26 pub fn new<A: Ord + 'static>(a: &'a A) -> Self {
27 OrdAny {
28 type_id: TypeId::of::<A>(),
29 cmp: |this, other| {
30 let this = unsafe { &*(this as *const A) };
33 let other = unsafe { &*(other as *const A) };
34 this.cmp(other)
35 },
36 val: a as *const A as *const (),
37 _marker: PhantomData,
38 }
39 }
40
41 #[inline]
43 pub fn type_id(&self) -> TypeId {
44 self.type_id
45 }
46}
47
48impl<'a> PartialEq for OrdAny<'a> {
49 #[inline]
50 fn eq(&self, other: &OrdAny<'a>) -> bool {
51 self.cmp(other) == Ordering::Equal
52 }
53}
54
55impl Eq for OrdAny<'_> {}
56
57impl<'a> PartialOrd for OrdAny<'a> {
58 #[inline]
59 fn partial_cmp(&self, other: &OrdAny<'a>) -> Option<Ordering> {
60 Some(self.cmp(other))
61 }
62}
63
64impl Ord for OrdAny<'_> {
66 #[inline]
67 fn cmp(&self, other: &Self) -> Ordering {
68 let type_cmp = self.type_id.cmp(&other.type_id);
69 if type_cmp != Ordering::Equal {
70 return type_cmp;
71 }
72 unsafe { (self.cmp)(self.val, other.val) }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use std::any::TypeId;
79 use std::cmp::Ordering;
80
81 use crate::OrdAny;
82
83 #[test]
84 fn test_ord_any() {
85 assert!(OrdAny::new(&1) < OrdAny::new(&2));
86 assert!(OrdAny::new(&true) > OrdAny::new(&false));
87 assert_eq!(
88 Ordering::Equal,
89 OrdAny::new(&String::new()).cmp(&OrdAny::new(&String::new()))
90 );
91 assert_eq!(
92 OrdAny::new(&1i32) < OrdAny::new(&true),
93 TypeId::of::<i32>() < TypeId::of::<bool>()
94 );
95 }
96}