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 {}