vexide_core/sync/
mutex.rs1use core::{
2 cell::UnsafeCell,
3 fmt::Debug,
4 sync::atomic::{AtomicBool, Ordering},
5};
6
7use futures_core::Future;
8use lock_api::RawMutex as _;
9
10struct MutexState(AtomicBool);
11impl MutexState {
12 const fn new() -> Self {
13 Self(AtomicBool::new(false))
14 }
15
16 fn try_lock(&self) -> bool {
18 self.0
19 .compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire)
20 .is_ok()
21 }
22
23 fn unlock(&self) {
24 self.0.store(false, Ordering::Release);
25 }
26}
27
28pub(crate) struct RawMutex {
30 state: MutexState,
31}
32impl RawMutex {
33 #[must_use]
35 #[allow(clippy::new_without_default)]
36 pub const fn new() -> Self {
37 Self {
38 state: MutexState::new(),
39 }
40 }
41}
42unsafe impl lock_api::RawMutex for RawMutex {
43 #[allow(clippy::declare_interior_mutable_const)]
45 const INIT: Self = Self::new();
46
47 type GuardMarker = lock_api::GuardSend;
48
49 fn lock(&self) {
50 while !self.state.try_lock() {
51 core::hint::spin_loop();
52 }
53 }
54
55 fn try_lock(&self) -> bool {
56 self.state.try_lock()
57 }
58
59 unsafe fn unlock(&self) {
60 self.state.unlock();
61 }
62}
63
64#[must_use = "futures do nothing unless you `.await` or poll them"]
66pub struct MutexLockFuture<'a, T: ?Sized> {
67 mutex: &'a Mutex<T>,
68}
69impl<'a, T> Future for MutexLockFuture<'a, T> {
70 type Output = MutexGuard<'a, T>;
71
72 fn poll(
73 self: core::pin::Pin<&mut Self>,
74 _: &mut core::task::Context<'_>,
75 ) -> core::task::Poll<Self::Output> {
76 if self.mutex.raw.try_lock() {
77 core::task::Poll::Ready(MutexGuard::new(self.mutex))
78 } else {
79 core::task::Poll::Pending
80 }
81 }
82}
83
84pub struct Mutex<T: ?Sized> {
87 raw: RawMutex,
88 data: UnsafeCell<T>,
89}
90unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
91unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
92
93impl<T> Mutex<T> {
94 pub const fn new(data: T) -> Self {
96 Self {
97 raw: RawMutex::new(),
98 data: UnsafeCell::new(data),
99 }
100 }
101}
102
103impl<T: ?Sized> Mutex<T> {
104 pub const fn lock(&self) -> MutexLockFuture<'_, T> {
107 MutexLockFuture { mutex: self }
108 }
109
110 pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
112 if self.raw.try_lock() {
113 Some(MutexGuard { mutex: self })
114 } else {
115 None
116 }
117 }
118
119 pub fn into_inner(self) -> T
121 where
122 T: Sized,
123 {
124 self.data.into_inner()
125 }
126
127 pub const fn get_mut(&mut self) -> &mut T {
129 self.data.get_mut()
130 }
131}
132
133impl<T> Debug for Mutex<T>
134where
135 T: ?Sized + Debug,
136{
137 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
138 struct Placeholder;
139 impl Debug for Placeholder {
140 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
141 f.write_str("<locked>")
142 }
143 }
144
145 let mut d = f.debug_struct("Mutex");
146 match self.try_lock() {
147 Some(guard) => d.field("data", &&*guard),
148 None => d.field("data", &Placeholder),
149 };
150 d.finish_non_exhaustive()
151 }
152}
153
154impl<T> Default for Mutex<T>
155where
156 T: Default,
157{
158 fn default() -> Self {
159 Self::new(T::default())
160 }
161}
162
163impl<T> From<T> for Mutex<T> {
164 fn from(value: T) -> Self {
165 Self::new(value)
166 }
167}
168
169#[derive(Debug)]
172#[must_use = "if unused the Mutex will immediately unlock"]
173#[clippy::has_significant_drop]
174pub struct MutexGuard<'a, T: ?Sized> {
175 mutex: &'a Mutex<T>,
176}
177
178impl<'a, T: ?Sized> MutexGuard<'a, T> {
179 const fn new(mutex: &'a Mutex<T>) -> Self {
180 Self { mutex }
181 }
182}
183
184impl<'a, T> MutexGuard<'a, T> {
185 pub(crate) unsafe fn unlock(&self) {
186 unsafe {
188 self.mutex.raw.unlock();
189 }
190 }
191
192 pub(crate) fn relock(self) -> MutexLockFuture<'a, T> {
193 let lock = self.mutex.lock();
194 drop(self);
195 lock
196 }
197}
198
199impl<T: ?Sized> core::ops::Deref for MutexGuard<'_, T> {
200 type Target = T;
201 fn deref(&self) -> &T {
202 unsafe { &*self.mutex.data.get() }
203 }
204}
205
206impl<T: ?Sized> core::ops::DerefMut for MutexGuard<'_, T> {
207 fn deref_mut(&mut self) -> &mut T {
208 unsafe { &mut *self.mutex.data.get() }
209 }
210}
211
212impl<T: ?Sized> Drop for MutexGuard<'_, T> {
213 fn drop(&mut self) {
214 unsafe { self.mutex.raw.unlock() };
215 }
216}