solar_data_structures/
interned.rs1use std::{
4    cmp::Ordering,
5    fmt::{self, Debug},
6    hash::{Hash, Hasher},
7    ops::Deref,
8    ptr,
9};
10
11#[allow(unnameable_types)]
12mod private {
13    #[derive(Clone, Copy, Debug)]
14    pub struct PrivateZst;
15}
16
17#[cfg_attr(feature = "nightly", rustc_pass_by_value)]
29pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst);
30
31impl<'a, T> Interned<'a, T> {
32    #[inline]
38    pub const fn new_unchecked(t: &'a T) -> Self {
39        Interned(t, private::PrivateZst)
40    }
41}
42
43impl<T> Clone for Interned<'_, T> {
44    fn clone(&self) -> Self {
45        *self
46    }
47}
48
49impl<T> Copy for Interned<'_, T> {}
50
51impl<T> Deref for Interned<'_, T> {
52    type Target = T;
53
54    #[inline]
55    fn deref(&self) -> &T {
56        self.0
57    }
58}
59
60impl<T> PartialEq for Interned<'_, T> {
61    #[inline]
62    fn eq(&self, other: &Self) -> bool {
63        ptr::eq(self.0, other.0)
65    }
66}
67
68impl<T> Eq for Interned<'_, T> {}
69
70impl<T: PartialOrd> PartialOrd for Interned<'_, T> {
71    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
72        if ptr::eq(self.0, other.0) {
75            Some(Ordering::Equal)
76        } else {
77            let res = self.0.partial_cmp(other.0);
78            debug_assert_ne!(res, Some(Ordering::Equal));
79            res
80        }
81    }
82}
83
84impl<T: Ord> Ord for Interned<'_, T> {
85    fn cmp(&self, other: &Self) -> Ordering {
86        if ptr::eq(self.0, other.0) {
89            Ordering::Equal
90        } else {
91            let res = self.0.cmp(other.0);
92            debug_assert_ne!(res, Ordering::Equal);
93            res
94        }
95    }
96}
97
98impl<T> Hash for Interned<'_, T> {
99    #[inline]
100    fn hash<H: Hasher>(&self, s: &mut H) {
101        ptr::hash(self.0, s)
103    }
104}
105
106impl<T: Debug> Debug for Interned<'_, T> {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        self.0.fmt(f)
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[derive(Debug)]
117    struct S(u32);
118
119    impl PartialEq for S {
120        fn eq(&self, _other: &Self) -> bool {
121            panic!("shouldn't be called");
122        }
123    }
124
125    impl Eq for S {}
126
127    #[allow(clippy::non_canonical_partial_ord_impl)]
128    impl PartialOrd for S {
129        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
130            assert_ne!(self.0, other.0);
132            self.0.partial_cmp(&other.0)
133        }
134    }
135
136    impl Ord for S {
137        fn cmp(&self, other: &Self) -> Ordering {
138            assert_ne!(self.0, other.0);
140            self.0.cmp(&other.0)
141        }
142    }
143
144    #[test]
145    fn test_uniq() {
146        let s1 = S(1);
147        let s2 = S(2);
148        let s3 = S(3);
149        let s4 = S(1); let v1 = Interned::new_unchecked(&s1);
152        let v2 = Interned::new_unchecked(&s2);
153        let v3a = Interned::new_unchecked(&s3);
154        let v3b = Interned::new_unchecked(&s3);
155        let v4 = Interned::new_unchecked(&s4); assert_ne!(v1, v2);
158        assert_ne!(v2, v3a);
159        assert_eq!(v1, v1);
160        assert_eq!(v3a, v3b);
161        assert_ne!(v1, v4); assert_eq!(v1.cmp(&v2), Ordering::Less);
164        assert_eq!(v3a.cmp(&v2), Ordering::Greater);
165        assert_eq!(v1.cmp(&v1), Ordering::Equal); assert_eq!(v3a.cmp(&v3b), Ordering::Equal); assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less));
169        assert_eq!(v3a.partial_cmp(&v2), Some(Ordering::Greater));
170        assert_eq!(v1.partial_cmp(&v1), Some(Ordering::Equal)); assert_eq!(v3a.partial_cmp(&v3b), Some(Ordering::Equal)); }
173}