1use alloc::alloc::Global;
2use core::alloc::Allocator;
3use core::cell::UnsafeCell;
4use core::fmt;
5use core::ops::{Deref, DerefMut};
6use crate::poison::{self, LockResult, TryLockError, TryLockResult};
7
8#[cfg(all(not(target_os="dos"), not(windows)))]
9mod posix;
10
11#[cfg(all(not(target_os="dos"), windows))]
12mod winapi;
13
14#[cfg(target_os="dos")]
15mod dos;
16
17#[cfg(all(not(target_os="dos"), not(windows)))]
18use posix::SysMutex;
19
20#[cfg(all(not(target_os="dos"), windows))]
21use winapi::SysMutex;
22
23#[cfg(target_os="dos")]
24use dos::SysMutex;
25
26pub struct Mutex<T: ?Sized, A: Allocator + Clone = Global> {
27 inner: SysMutex<A>,
28 poison: poison::Flag,
29 data: UnsafeCell<T>,
30}
31
32unsafe impl<T: ?Sized + Send, A: Allocator + Clone> Send for Mutex<T, A> { }
33
34unsafe impl<T: ?Sized + Send, A: Allocator + Clone> Sync for Mutex<T, A> { }
35
36#[must_use="if unused the Mutex will immediately unlock"]
37pub struct MutexGuard<'a, T: ?Sized + 'a, A: Allocator + Clone = Global> {
38 lock: &'a Mutex<T, A>,
39 poison: poison::Guard,
40}
41
42impl<T: ?Sized, A: Allocator + Clone> !Send for MutexGuard<'_, T, A> { }
43
44unsafe impl<T: ?Sized + Sync, A: Allocator + Clone> Sync for MutexGuard<'_, T, A> { }
45
46impl<T, A: Allocator + Clone> Mutex<T, A> {
47 pub const fn new_in(t: T, allocator: A) -> Mutex<T, A> {
48 Mutex { inner: SysMutex::new_in(allocator), poison: poison::Flag::new(), data: UnsafeCell::new(t) }
49 }
50
51 pub const fn allocator(&self) -> &A { self.inner.allocator() }
52}
53
54impl<T> Mutex<T> {
55 pub const fn new(t: T) -> Mutex<T> {
56 Mutex::new_in(t, Global)
57 }
58}
59
60impl<T: ?Sized, A: Allocator + Clone> Mutex<T, A> {
61 pub fn lock(&self) -> LockResult<MutexGuard<'_, T, A>> {
62 unsafe {
63 self.inner.lock();
64 MutexGuard::new(self)
65 }
66 }
67
68 pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T, A>> {
69 unsafe {
70 if self.inner.try_lock() {
71 Ok(MutexGuard::new(self)?)
72 } else {
73 Err(TryLockError::WouldBlock)
74 }
75 }
76 }
77
78 pub fn is_poisoned(&self) -> bool {
79 self.poison.get()
80 }
81
82 pub fn clear_poison(&self) {
83 self.poison.clear();
84 }
85
86 pub fn into_inner(self) -> LockResult<T>
87 where
88 T: Sized,
89 {
90 let data = self.data.into_inner();
91 poison::map_result(self.poison.borrow(), |()| data)
92 }
93
94 pub fn get_mut(&mut self) -> LockResult<&mut T> {
95 let data = self.data.get_mut();
96 poison::map_result(self.poison.borrow(), |()| data)
97 }
98}
99
100impl<T> From<T> for Mutex<T> {
101 fn from(t: T) -> Self {
102 Mutex::new(t)
103 }
104}
105
106impl<T: Default> Default for Mutex<T> {
107 fn default() -> Mutex<T> {
108 Mutex::new(Default::default())
109 }
110}
111
112impl<T: ?Sized + fmt::Debug, A: Allocator + Clone> fmt::Debug for Mutex<T, A> {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 let mut d = f.debug_struct("Mutex");
115 match self.try_lock() {
116 Ok(guard) => {
117 d.field("data", &&*guard);
118 }
119 Err(TryLockError::Poisoned(err)) => {
120 d.field("data", &&**err.get_ref());
121 }
122 Err(TryLockError::WouldBlock) => {
123 d.field("data", &format_args!("<locked>"));
124 }
125 }
126 d.field("poisoned", &self.poison.get());
127 d.finish_non_exhaustive()
128 }
129}
130
131impl<'mutex, T: ?Sized, A: Allocator + Clone> MutexGuard<'mutex, T, A> {
132 unsafe fn new(lock: &'mutex Mutex<T, A>) -> LockResult<MutexGuard<'mutex, T, A>> {
133 poison::map_result(lock.poison.guard(), |guard| MutexGuard { lock, poison: guard })
134 }
135}
136
137impl<T: ?Sized, A: Allocator + Clone> Deref for MutexGuard<'_, T, A> {
138 type Target = T;
139
140 fn deref(&self) -> &T {
141 unsafe { &*self.lock.data.get() }
142 }
143}
144
145impl<T: ?Sized, A: Allocator + Clone> DerefMut for MutexGuard<'_, T, A> {
146 fn deref_mut(&mut self) -> &mut T {
147 unsafe { &mut *self.lock.data.get() }
148 }
149}
150
151impl<T: ?Sized, A: Allocator + Clone> Drop for MutexGuard<'_, T, A> {
152 fn drop(&mut self) {
153 unsafe {
154 self.lock.poison.done(&self.poison);
155 self.lock.inner.unlock();
156 }
157 }
158}
159
160impl<T: ?Sized + fmt::Debug, A: Allocator + Clone> fmt::Debug for MutexGuard<'_, T, A> {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 fmt::Debug::fmt(&**self, f)
163 }
164}
165
166impl<T: ?Sized + fmt::Display, A: Allocator + Clone> fmt::Display for MutexGuard<'_, T, A> {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 (**self).fmt(f)
169 }
170}