1use core::cell::Cell;
2use core::fmt;
3use core::mem::ManuallyDrop;
4use core::ptr::NonNull;
5
6const EXCLUSIVE: usize = 1usize.rotate_right(2);
8const MOVED: usize = 1usize.rotate_right(1);
10const MASK: usize = EXCLUSIVE | MOVED;
12
13#[derive(Debug)]
21#[cfg_attr(test, derive(PartialEq))]
22#[non_exhaustive]
23pub struct AccessError {
24 kind: AccessErrorKind,
25}
26
27impl AccessError {
28 #[inline]
29 const fn new(kind: AccessErrorKind) -> Self {
30 Self { kind }
31 }
32}
33
34impl fmt::Display for AccessError {
35 #[inline]
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match &self.kind {
38 AccessErrorKind::NotAccessibleRef(s) => write!(
39 f,
40 "Cannot read, value has snapshot {s} and is not available for reading"
41 ),
42 AccessErrorKind::NotAccessibleMut(s) => write!(
43 f,
44 "Cannot write, value has snapshot {s} and is not available for writing"
45 ),
46 AccessErrorKind::NotAccessibleTake(s) => write!(
47 f,
48 "Cannot take, value has snapshot {s} and is not available for taking"
49 ),
50 }
51 }
52}
53
54impl core::error::Error for AccessError {}
55
56#[derive(Debug)]
57#[cfg_attr(test, derive(PartialEq))]
58enum AccessErrorKind {
59 NotAccessibleRef(Snapshot),
60 NotAccessibleMut(Snapshot),
61 NotAccessibleTake(Snapshot),
62}
63
64#[derive(PartialEq)]
67#[repr(transparent)]
68pub(crate) struct Snapshot(usize);
69
70impl Snapshot {
71 pub(crate) fn is_readable(&self) -> bool {
73 self.0 & MASK == 0
74 }
75
76 pub(crate) fn is_writable(&self) -> bool {
78 self.0 & MASK == 0
79 }
80
81 pub(crate) fn is_exclusive(&self) -> bool {
83 self.0 & MASK != 0
84 }
85
86 pub(crate) fn shared(&self) -> usize {
88 self.0 & !MASK
89 }
90}
91
92impl fmt::Display for Snapshot {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 if self.0 & MOVED != 0 {
95 write!(f, "M")?;
96 } else {
97 write!(f, "-")?;
98 }
99
100 if self.0 & EXCLUSIVE != 0 {
101 write!(f, "X")?;
102 } else {
103 write!(f, "-")?;
104 }
105
106 write!(f, "{:06}", self.shared())?;
107 Ok(())
108 }
109}
110
111impl fmt::Debug for Snapshot {
112 #[inline]
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 write!(f, "Snapshot({self})")
115 }
116}
117
118#[repr(transparent)]
125pub(crate) struct Access(Cell<usize>);
126
127impl Access {
128 pub(crate) const fn new() -> Self {
130 Self(Cell::new(0))
131 }
132
133 #[inline(always)]
135 pub(crate) fn is_shared(&self) -> bool {
136 self.0.get() & MASK == 0
137 }
138
139 #[inline(always)]
142 pub(crate) fn is_exclusive(&self) -> bool {
143 self.0.get() == 0
144 }
145
146 #[inline(always)]
148 pub(crate) fn is_taken(&self) -> bool {
149 self.0.get() & MOVED != 0
150 }
151
152 pub(crate) fn shared(&self) -> Result<AccessGuard<'_>, AccessError> {
154 self.try_shared()?;
155 Ok(AccessGuard(self))
156 }
157
158 #[inline(always)]
159 pub(crate) fn try_shared(&self) -> Result<(), AccessError> {
160 let state = self.0.get();
161
162 if state & MASK != 0 {
163 debug_assert_eq!(
164 state & !MASK,
165 0,
166 "count should be zero, but was {}",
167 Snapshot(state)
168 );
169 return Err(AccessError::new(AccessErrorKind::NotAccessibleRef(
170 Snapshot(state),
171 )));
172 }
173
174 if state == !MASK {
176 crate::alloc::abort();
177 }
178
179 self.0.set(state + 1);
180 Ok(())
181 }
182
183 #[inline(always)]
185 pub(crate) fn exclusive(&self) -> Result<AccessGuard<'_>, AccessError> {
186 self.try_exclusive()?;
187 Ok(AccessGuard(self))
188 }
189
190 #[inline(always)]
191 pub(crate) fn try_exclusive(&self) -> Result<(), AccessError> {
192 let state = self.0.get();
193
194 if state != 0 {
195 return Err(AccessError::new(AccessErrorKind::NotAccessibleMut(
196 Snapshot(state),
197 )));
198 }
199
200 self.0.set(state | EXCLUSIVE);
201 Ok(())
202 }
203
204 #[inline(always)]
208 pub(crate) fn try_take(&self) -> Result<(), AccessError> {
209 let state = self.0.get();
210
211 if state != 0 {
212 return Err(AccessError::new(AccessErrorKind::NotAccessibleTake(
213 Snapshot(state),
214 )));
215 }
216
217 self.0.set(state | MOVED);
218 Ok(())
219 }
220
221 #[inline(always)]
223 pub(crate) fn take(&self) {
224 let state = self.0.get();
225 self.0.set(state | MOVED);
226 }
227
228 #[inline(always)]
230 pub(super) fn release(&self) {
231 let b = self.0.get();
232
233 let b = if b & EXCLUSIVE != 0 {
234 b & !EXCLUSIVE
235 } else {
236 debug_assert_ne!(b & !MASK, 0, "count should be zero but was {}", Snapshot(b));
237 b - 1
238 };
239
240 self.0.set(b);
241 }
242
243 #[inline(always)]
245 pub(super) fn snapshot(&self) -> Snapshot {
246 Snapshot(self.0.get())
247 }
248}
249
250impl fmt::Debug for Access {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 write!(f, "{}", Snapshot(self.0.get()))
253 }
254}
255
256#[repr(transparent)]
258pub(crate) struct AccessGuard<'a>(&'a Access);
259
260impl AccessGuard<'_> {
261 pub(crate) unsafe fn into_raw(self) -> RawAccessGuard {
269 RawAccessGuard(NonNull::from(ManuallyDrop::new(self).0))
270 }
271}
272
273impl Drop for AccessGuard<'_> {
274 fn drop(&mut self) {
275 self.0.release();
276 }
277}
278
279#[repr(transparent)]
281pub(crate) struct RawAccessGuard(NonNull<Access>);
282
283impl Drop for RawAccessGuard {
284 fn drop(&mut self) {
285 unsafe { self.0.as_ref().release() }
286 }
287}