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!(f, "Cannot read, {}", s.what()),
39 AccessErrorKind::NotAccessibleMut(s) => write!(f, "Cannot write, {}", s.what()),
40 AccessErrorKind::NotAccessibleTake(s) => write!(f, "Cannot take, {}", s.what()),
41 }
42 }
43}
44
45impl core::error::Error for AccessError {}
46
47#[derive(Debug)]
48#[cfg_attr(test, derive(PartialEq))]
49enum AccessErrorKind {
50 NotAccessibleRef(Snapshot),
51 NotAccessibleMut(Snapshot),
52 NotAccessibleTake(Snapshot),
53}
54
55#[derive(PartialEq)]
58#[repr(transparent)]
59pub(crate) struct Snapshot(usize);
60
61impl Snapshot {
62 pub(crate) fn is_readable(&self) -> bool {
64 self.0 & MASK == 0
65 }
66
67 pub(crate) fn is_writable(&self) -> bool {
69 self.0 & MASK == 0
70 }
71
72 pub(crate) fn is_exclusive(&self) -> bool {
74 self.0 & MASK != 0
75 }
76
77 pub(crate) fn shared(&self) -> usize {
79 self.0 & !MASK
80 }
81
82 fn what(&self) -> &'static str {
89 if self.0 & MOVED != 0 {
90 "the value has been moved"
91 } else if self.0 & EXCLUSIVE != 0 {
92 "the value is being written to"
93 } else if self.shared() > 0 {
94 "the value is being read from"
95 } else {
96 "the value is not available"
97 }
98 }
99}
100
101impl fmt::Display for Snapshot {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 if self.0 & MOVED != 0 {
104 write!(f, "M")?;
105 } else {
106 write!(f, "-")?;
107 }
108
109 if self.0 & EXCLUSIVE != 0 {
110 write!(f, "X")?;
111 } else {
112 write!(f, "-")?;
113 }
114
115 write!(f, "{:06}", self.shared())?;
116 Ok(())
117 }
118}
119
120impl fmt::Debug for Snapshot {
121 #[inline]
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(f, "Snapshot({self})")
124 }
125}
126
127#[repr(transparent)]
134pub(crate) struct Access(Cell<usize>);
135
136impl Access {
137 pub(crate) const fn new() -> Self {
139 Self(Cell::new(0))
140 }
141
142 #[inline(always)]
144 pub(crate) fn is_shared(&self) -> bool {
145 self.0.get() & MASK == 0
146 }
147
148 #[inline(always)]
151 pub(crate) fn is_exclusive(&self) -> bool {
152 self.0.get() == 0
153 }
154
155 #[inline(always)]
157 pub(crate) fn is_taken(&self) -> bool {
158 self.0.get() & MOVED != 0
159 }
160
161 pub(crate) fn shared(&self) -> Result<AccessGuard<'_>, AccessError> {
163 self.try_shared()?;
164 Ok(AccessGuard(self))
165 }
166
167 #[inline(always)]
168 pub(crate) fn try_shared(&self) -> Result<(), AccessError> {
169 let state = self.0.get();
170
171 if state & MASK != 0 {
172 debug_assert_eq!(
173 state & !MASK,
174 0,
175 "count should be zero, but was {}",
176 Snapshot(state)
177 );
178 return Err(AccessError::new(AccessErrorKind::NotAccessibleRef(
179 Snapshot(state),
180 )));
181 }
182
183 if state == !MASK {
185 crate::alloc::abort();
186 }
187
188 self.0.set(state + 1);
189 Ok(())
190 }
191
192 #[inline(always)]
194 pub(crate) fn exclusive(&self) -> Result<AccessGuard<'_>, AccessError> {
195 self.try_exclusive()?;
196 Ok(AccessGuard(self))
197 }
198
199 #[inline(always)]
200 pub(crate) fn try_exclusive(&self) -> Result<(), AccessError> {
201 let state = self.0.get();
202
203 if state != 0 {
204 return Err(AccessError::new(AccessErrorKind::NotAccessibleMut(
205 Snapshot(state),
206 )));
207 }
208
209 self.0.set(state | EXCLUSIVE);
210 Ok(())
211 }
212
213 #[inline(always)]
217 pub(crate) fn try_take(&self) -> Result<(), AccessError> {
218 let state = self.0.get();
219
220 if state != 0 {
221 return Err(AccessError::new(AccessErrorKind::NotAccessibleTake(
222 Snapshot(state),
223 )));
224 }
225
226 self.0.set(state | MOVED);
227 Ok(())
228 }
229
230 #[inline(always)]
232 pub(crate) fn take(&self) {
233 let state = self.0.get();
234 self.0.set(state | MOVED);
235 }
236
237 #[inline(always)]
239 pub(super) fn release(&self) {
240 let b = self.0.get();
241
242 let b = if b & EXCLUSIVE != 0 {
243 b & !EXCLUSIVE
244 } else {
245 debug_assert_ne!(b & !MASK, 0, "count should be zero but was {}", Snapshot(b));
246 b - 1
247 };
248
249 self.0.set(b);
250 }
251
252 #[inline(always)]
254 pub(super) fn snapshot(&self) -> Snapshot {
255 Snapshot(self.0.get())
256 }
257}
258
259impl fmt::Debug for Access {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 write!(f, "{}", Snapshot(self.0.get()))
262 }
263}
264
265#[repr(transparent)]
267pub(crate) struct AccessGuard<'a>(&'a Access);
268
269impl AccessGuard<'_> {
270 pub(crate) unsafe fn into_raw(self) -> RawAccessGuard {
278 RawAccessGuard(NonNull::from(ManuallyDrop::new(self).0))
279 }
280}
281
282impl Drop for AccessGuard<'_> {
283 fn drop(&mut self) {
284 self.0.release();
285 }
286}
287
288#[repr(transparent)]
290pub(crate) struct RawAccessGuard(NonNull<Access>);
291
292impl Drop for RawAccessGuard {
293 fn drop(&mut self) {
294 unsafe { self.0.as_ref().release() }
295 }
296}