shrev/
util.rs

1use std::{
2    fmt::{self, Debug, Formatter},
3    sync::Arc,
4};
5
6/// A unique ID that can be used to assert two objects refer to another common
7/// object.
8///
9/// Example:
10///
11/// We have an allocator type which allocates `Foo`s. Some operations could
12/// cause bugs if two `Foo`s from different allocators are used; `InstanceId`
13/// can assert that both are from the same allocator by comparing their
14/// `InstanceId`.
15#[derive(Debug)]
16pub struct InstanceId {
17    inner: Arc<u8>,
18    msg: &'static str,
19}
20
21impl InstanceId {
22    /// Creates a new, unique instance id.
23    pub fn new(msg: &'static str) -> Self {
24        InstanceId {
25            inner: Arc::default(),
26            msg,
27        }
28    }
29
30    /// Returns the unique `usize` representation which is used for all the
31    /// assertions.
32    #[inline]
33    pub fn as_usize(&self) -> usize {
34        self.inner.as_ref() as *const _ as usize
35    }
36
37    /// Check if `self` and `reference` are equal, panic otherwise.
38    #[inline]
39    pub fn assert_eq(&self, reference: &Reference) {
40        assert_eq!(self, reference, "{}", self.msg);
41    }
42
43    /// Creates a "reference" of this instance id. This is essentially like
44    /// cloning, but `InstanceId`s don't implement `Clone` on purpose since
45    /// values caring it should never be cloned.
46    #[inline]
47    pub fn reference(&self) -> Reference {
48        Reference {
49            inner: self.inner.clone(),
50        }
51    }
52}
53
54impl PartialEq<Reference> for InstanceId {
55    #[inline]
56    fn eq(&self, reference: &Reference) -> bool {
57        self.as_usize() == reference.as_usize()
58    }
59}
60
61/// A reference to an `InstanceId`.
62#[derive(Debug, Default)]
63pub struct Reference {
64    inner: Arc<u8>,
65}
66
67impl Reference {
68    /// Returns the `usize` representation of the referenced instance id which
69    /// is used for all the assertions.
70    #[inline]
71    pub fn as_usize(&self) -> usize {
72        self.inner.as_ref() as *const _ as usize
73    }
74}
75
76impl Eq for Reference {}
77
78impl PartialEq for Reference {
79    fn eq(&self, other: &Reference) -> bool {
80        self.as_usize() == other.as_usize()
81    }
82}
83
84/// A struct which implements `Sync` for non-`Sync` types by only allowing
85/// mutable access.
86///
87/// > Is this safe?
88///
89/// Yes. The `Sync` marker trait guarantees that `&T` is safe to send to another
90/// thread. The reason this is not implemented for some types is that they have
91/// interior mutability, i.e. you can change their state with an immutable
92/// borrow. That's often not thread safe.
93///
94/// `NoSharedAccess` implements `Sync` for the only purpose of making the
95/// containing struct `Sync`; there's no use in using `NoSharedAccess` in
96/// isolation since it doesn't add anything new; it simply disallows immutable
97/// access.
98pub struct NoSharedAccess<T>(T);
99
100impl<T> NoSharedAccess<T> {
101    pub fn new(t: T) -> Self {
102        NoSharedAccess(t)
103    }
104
105    pub fn get_mut(&mut self) -> &mut T {
106        &mut self.0
107    }
108}
109
110impl<T> Debug for NoSharedAccess<T>
111where
112    T: Debug,
113{
114    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
115        self.0.fmt(f)
116    }
117}
118
119unsafe impl<T> Sync for NoSharedAccess<T> where for<'a> &'a mut NoSharedAccess<T>: Send {}