object_id/
lib.rs

1#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "README.md" ) ) ]
2
3use std::{pin::Pin, ptr};
4
5#[derive(Clone)]
6pub struct UniqueId {
7    // Box itself is a guarantee that the pointer to the covered is not modified, Pin is added just
8    // to ensure it by 200%
9    inner: Pin<Box<u8>>,
10}
11
12impl Default for UniqueId {
13    fn default() -> Self {
14        Self { inner: Box::pin(0) }
15    }
16}
17
18impl core::fmt::Debug for UniqueId {
19    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
20        write!(f, "{}", self.as_usize())
21    }
22}
23impl core::hash::Hash for UniqueId {
24    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
25        self.as_usize().hash(state);
26    }
27}
28
29impl PartialEq for UniqueId {
30    fn eq(&self, other: &Self) -> bool {
31        ptr::eq(&*self.inner, &*other.inner)
32    }
33}
34
35impl PartialOrd for UniqueId {
36    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
37        Some(self.as_usize().cmp(&other.as_usize()))
38    }
39}
40
41impl Ord for UniqueId {
42    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
43        self.as_usize().cmp(&other.as_usize())
44    }
45}
46
47impl Eq for UniqueId {}
48
49impl UniqueId {
50    pub fn new() -> Self {
51        Self::default()
52    }
53
54    pub fn as_usize(&self) -> usize {
55        ptr::addr_of!(*self.inner) as usize
56    }
57}
58
59#[cfg(test)]
60mod test {
61    use std::sync::Arc;
62
63    use crate::UniqueId;
64
65    #[derive(Clone, Eq, PartialEq, Debug)]
66    struct Test {
67        id: UniqueId,
68    }
69
70    struct TestWrapper {
71        inner: Arc<Test>,
72    }
73
74    impl Clone for TestWrapper {
75        fn clone(&self) -> Self {
76            Self {
77                inner: self.inner.clone(),
78            }
79        }
80    }
81
82    impl TestWrapper {
83        fn new() -> Self {
84            Self {
85                inner: Test { id: <_>::default() }.into(),
86            }
87        }
88        fn id(&self) -> usize {
89            self.inner.id.as_usize()
90        }
91    }
92
93    #[cfg(not(debug_assertions))]
94    #[test]
95    fn test_stack() {
96        panic!(
97            "the test MUST be run for the debug target as there is still a chance the object
98generator may be inlined"
99        );
100    }
101    #[cfg(debug_assertions)]
102    #[test]
103    fn test_stack() {
104        #[inline(never)]
105        fn generate() -> (Test, usize) {
106            let t = Test { id: <_>::default() };
107            let n = t.id.as_usize();
108            (t, n)
109        }
110        let (t, n) = generate();
111        assert_eq!(t.id.as_usize(), n);
112    }
113    #[test]
114    fn test_clone_eq() {
115        let t = Test { id: <_>::default() };
116        let t2 = t.clone();
117        assert_ne!(t.id, t2.id);
118        assert_ne!(t.id.as_usize(), t2.id.as_usize());
119        assert_ne!(t, t2);
120        assert_eq!(t, t);
121        assert_eq!(t.id, t.id);
122    }
123    #[test]
124    fn test_heap_movement() {
125        let t = Test { id: <_>::default() };
126        let n = t.id.as_usize();
127        let mut x = vec![t];
128        assert_eq!(x[0].id.as_usize(), n);
129        let t_back = x.pop().unwrap();
130        assert_eq!(t_back.id.as_usize(), n);
131    }
132    #[test]
133    fn test_arc_covered() {
134        let t1 = TestWrapper::new();
135        let t2 = t1.clone();
136        assert_eq!(t1.id(), t2.id());
137    }
138}