1#![cfg(any(target_os = "macos", target_os = "ios"))]
2#![no_std]
3#![cfg_attr(feature = "nightly", feature(coerce_unsized, unsize))]
4
5use core::cell::UnsafeCell;
6use core::default::Default;
7use core::fmt::{self, Debug, Display, Formatter};
8use core::marker::PhantomData;
9use core::ops::{Deref, DerefMut, Drop};
10
11#[allow(non_camel_case_types)]
12pub mod sys {
13 #[repr(C)]
14 pub struct os_unfair_lock(pub u32);
15
16 pub type os_unfair_lock_t = *mut os_unfair_lock;
17 pub type os_unfair_lock_s = os_unfair_lock;
18
19 pub const OS_UNFAIR_LOCK_INIT: os_unfair_lock = os_unfair_lock(0);
20
21 extern "C" {
22 pub fn os_unfair_lock_lock(lock: os_unfair_lock_t);
24 pub fn os_unfair_lock_unlock(lock: os_unfair_lock_t);
25 pub fn os_unfair_lock_trylock(lock: os_unfair_lock_t) -> bool;
26 pub fn os_unfair_lock_assert_owner(lock: os_unfair_lock_t);
27 pub fn os_unfair_lock_assert_not_owner(lock: os_unfair_lock_t);
28 }
29}
30
31pub struct Mutex<T: ?Sized> {
32 pub lock: UnsafeCell<sys::os_unfair_lock>,
33 pub cell: UnsafeCell<T>,
34}
35
36struct CantSendMutexGuardBetweenThreads;
37
38pub struct MutexGuard<'a, T: ?Sized> {
39 pub mutex: &'a Mutex<T>,
40 pd: PhantomData<*const CantSendMutexGuardBetweenThreads>,
42}
43
44unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
45unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
46
47impl<T: ?Sized> Mutex<T> {
48 #[inline]
49 pub const fn new(value: T) -> Self
50 where
51 T: Sized,
52 {
53 Mutex {
54 lock: UnsafeCell::new(sys::OS_UNFAIR_LOCK_INIT),
55 cell: UnsafeCell::new(value),
56 }
57 }
58 #[inline]
59 pub fn lock<'a>(&'a self) -> MutexGuard<'a, T> {
60 unsafe {
61 sys::os_unfair_lock_lock(self.lock.get());
62 }
63 MutexGuard {
64 mutex: self,
65 pd: PhantomData,
66 }
67 }
68 #[inline]
69 pub fn try_lock<'a>(&'a self) -> Option<MutexGuard<'a, T>> {
70 let ok = unsafe { sys::os_unfair_lock_trylock(self.lock.get()) };
71 if ok {
72 Some(MutexGuard {
73 mutex: self,
74 pd: PhantomData,
75 })
76 } else {
77 None
78 }
79 }
80 #[inline]
81 pub fn assert_not_owner(&self) {
82 unsafe {
83 sys::os_unfair_lock_assert_not_owner(self.lock.get());
84 }
85 }
86 #[inline]
87 pub fn into_inner(self) -> T
88 where
89 T: Sized,
90 {
91 self.cell.into_inner()
92 }
93}
94
95unsafe impl<'a, T: ?Sized + Sync> Sync for MutexGuard<'a, T> {}
98
99impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
100 type Target = T;
101 #[inline]
102 fn deref(&self) -> &T {
103 unsafe { &*self.mutex.cell.get() }
104 }
105}
106
107impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
108 #[inline]
109 fn deref_mut(&mut self) -> &mut T {
110 unsafe { &mut *self.mutex.cell.get() }
111 }
112}
113
114impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
115 #[inline]
116 fn drop(&mut self) {
117 unsafe {
118 sys::os_unfair_lock_unlock(self.mutex.lock.get());
119 }
120 }
121}
122
123impl<T: ?Sized + Default> Default for Mutex<T> {
126 #[inline]
127 fn default() -> Self {
128 Mutex::new(T::default())
129 }
130}
131
132impl<T: ?Sized + Debug> Debug for Mutex<T> {
133 #[inline]
134 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
135 self.lock().fmt(f)
136 }
137}
138
139impl<T: ?Sized + Display> Display for Mutex<T> {
140 #[inline]
141 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
142 self.lock().fmt(f)
143 }
144}
145
146impl<T> From<T> for Mutex<T> {
147 #[inline]
148 fn from(t: T) -> Mutex<T> {
149 Mutex::new(t)
150 }
151}
152
153#[cfg(feature = "nightly")]
154impl<T, U> core::ops::CoerceUnsized<Mutex<U>> for Mutex<T> where T: core::ops::CoerceUnsized<U> {}
155
156impl<'a, T: ?Sized + Debug> Debug for MutexGuard<'a, T> {
159 #[inline]
160 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
161 (**self).fmt(f)
162 }
163}
164
165impl<'a, T: ?Sized + Display> Display for MutexGuard<'a, T> {
166 #[inline]
167 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
168 (**self).fmt(f)
169 }
170}
171
172#[cfg(feature = "nightly")]
173impl<'a, T: ?Sized, U: ?Sized> core::ops::CoerceUnsized<MutexGuard<'a, U>> for MutexGuard<'a, T> where
174 T: core::marker::Unsize<U>
175{
176}
177
178#[cfg(test)]
179mod tests {
180 use super::Mutex;
181 const TEST_CONST: Mutex<u32> = Mutex::new(42);
182 #[test]
183 fn basics() {
184 let m = TEST_CONST;
185 *m.lock() += 1;
186 {
187 let mut g = m.try_lock().unwrap();
188 *g += 1;
189 assert!(m.try_lock().is_none());
190 }
191 m.assert_not_owner();
192 assert_eq!(*m.lock(), 44);
193 assert_eq!(m.into_inner(), 44);
194 }
195 #[test]
196 #[cfg(feature = "nightly")]
197 fn unsize() {
198 use super::MutexGuard;
199 let m: Mutex<[u8; 1]> = Mutex::new([100]);
200 (&m as &Mutex<[u8]>).lock()[0] += 1;
201 (m.lock() as MutexGuard<'_, [u8]>)[0] += 1;
202 let n: Mutex<&'static [u8; 1]> = Mutex::new(&[200]);
203 let _: Mutex<&'static [u8]> = n;
204 }
205}