1 | /* |
2 | * Copyright 2020 Actyx AG |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | //! A mutual exclusion primitive that relies on static type information only |
17 | //! |
18 | //! This library is inspired by [this discussion](https://internals.rust-lang.org/t/what-shall-sync-mean-across-an-await/12020/2). |
19 | #![doc (html_logo_url = "https://developer.actyx.com/img/logo.svg" )] |
20 | #![doc (html_favicon_url = "https://developer.actyx.com/img/favicon.ico" )] |
21 | #![no_std ] |
22 | |
23 | use core::{ |
24 | fmt::{self, Debug, Formatter}, |
25 | pin::Pin, |
26 | future::Future, |
27 | task::{Context, Poll}, |
28 | }; |
29 | |
30 | /// A mutual exclusion primitive that relies on static type information only |
31 | /// |
32 | /// In some cases synchronization can be proven statically: whenever you hold an exclusive `&mut` |
33 | /// reference, the Rust type system ensures that no other part of the program can hold another |
34 | /// reference to the data. Therefore it is safe to access it even if the current thread obtained |
35 | /// this reference via a channel. Whenever this is the case, the overhead of allocating and locking |
36 | /// a [`Mutex`] can be avoided by using this static version. |
37 | /// |
38 | /// One example where this is often applicable is [`Future`], which requires an exclusive reference |
39 | /// for its [`poll`] method: While a given `Future` implementation may not be safe to access by |
40 | /// multiple threads concurrently, the executor can only run the `Future` on one thread at any |
41 | /// given time, making it [`Sync`] in practice as long as the implementation is `Send`. You can |
42 | /// therefore use the static mutex to prove that your data structure is `Sync` even though it |
43 | /// contains such a `Future`. |
44 | /// |
45 | /// # Example |
46 | /// |
47 | /// ``` |
48 | /// use sync_wrapper::SyncWrapper; |
49 | /// use std::future::Future; |
50 | /// |
51 | /// struct MyThing { |
52 | /// future: SyncWrapper<Box<dyn Future<Output = String> + Send>>, |
53 | /// } |
54 | /// |
55 | /// impl MyThing { |
56 | /// // all accesses to `self.future` now require an exclusive reference or ownership |
57 | /// } |
58 | /// |
59 | /// fn assert_sync<T: Sync>() {} |
60 | /// |
61 | /// assert_sync::<MyThing>(); |
62 | /// ``` |
63 | /// |
64 | /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html |
65 | /// [`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html |
66 | /// [`poll`]: https://doc.rust-lang.org/std/future/trait.Future.html#method.poll |
67 | /// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html |
68 | #[repr (transparent)] |
69 | pub struct SyncWrapper<T>(T); |
70 | |
71 | impl<T> SyncWrapper<T> { |
72 | /// Creates a new static mutex containing the given value. |
73 | /// |
74 | /// # Examples |
75 | /// |
76 | /// ``` |
77 | /// use sync_wrapper::SyncWrapper; |
78 | /// |
79 | /// let mutex = SyncWrapper::new(42); |
80 | /// ``` |
81 | pub const fn new(value: T) -> Self { |
82 | Self(value) |
83 | } |
84 | |
85 | /// Acquires a reference to the protected value. |
86 | /// |
87 | /// This is safe because it requires an exclusive reference to the mutex. Therefore this method |
88 | /// neither panics nor does it return an error. This is in contrast to [`Mutex::get_mut`] which |
89 | /// returns an error if another thread panicked while holding the lock. It is not recommended |
90 | /// to send an exclusive reference to a potentially damaged value to another thread for further |
91 | /// processing. |
92 | /// |
93 | /// [`Mutex::get_mut`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.get_mut |
94 | /// |
95 | /// # Examples |
96 | /// |
97 | /// ``` |
98 | /// use sync_wrapper::SyncWrapper; |
99 | /// |
100 | /// let mut mutex = SyncWrapper::new(42); |
101 | /// let value = mutex.get_mut(); |
102 | /// *value = 0; |
103 | /// assert_eq!(*mutex.get_mut(), 0); |
104 | /// ``` |
105 | pub fn get_mut(&mut self) -> &mut T { |
106 | &mut self.0 |
107 | } |
108 | |
109 | /// Acquires a pinned reference to the protected value. |
110 | /// |
111 | /// See [`Self::get_mut`] for why this method is safe. |
112 | /// |
113 | /// # Examples |
114 | /// |
115 | /// ``` |
116 | /// use std::future::Future; |
117 | /// use std::pin::Pin; |
118 | /// use std::task::{Context, Poll}; |
119 | /// |
120 | /// use pin_project_lite::pin_project; |
121 | /// use sync_wrapper::SyncWrapper; |
122 | /// |
123 | /// pin_project! { |
124 | /// struct FutureWrapper<F> { |
125 | /// #[pin] |
126 | /// inner: SyncWrapper<F>, |
127 | /// } |
128 | /// } |
129 | /// |
130 | /// impl<F: Future> Future for FutureWrapper<F> { |
131 | /// type Output = F::Output; |
132 | /// |
133 | /// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
134 | /// self.project().inner.get_pin_mut().poll(cx) |
135 | /// } |
136 | /// } |
137 | /// ``` |
138 | pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { |
139 | unsafe { Pin::map_unchecked_mut(self, |this| &mut this.0) } |
140 | } |
141 | |
142 | /// Consumes this mutex, returning the underlying data. |
143 | /// |
144 | /// This is safe because it requires ownership of the mutex, therefore this method will neither |
145 | /// panic nor does it return an error. This is in contrast to [`Mutex::into_inner`] which |
146 | /// returns an error if another thread panicked while holding the lock. It is not recommended |
147 | /// to send an exclusive reference to a potentially damaged value to another thread for further |
148 | /// processing. |
149 | /// |
150 | /// [`Mutex::into_inner`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.into_inner |
151 | /// |
152 | /// # Examples |
153 | /// |
154 | /// ``` |
155 | /// use sync_wrapper::SyncWrapper; |
156 | /// |
157 | /// let mut mutex = SyncWrapper::new(42); |
158 | /// assert_eq!(mutex.into_inner(), 42); |
159 | /// ``` |
160 | pub fn into_inner(self) -> T { |
161 | self.0 |
162 | } |
163 | } |
164 | |
165 | // this is safe because the only operations permitted on this data structure require exclusive |
166 | // access or ownership |
167 | unsafe impl<T> Sync for SyncWrapper<T> {} |
168 | |
169 | impl<T> Debug for SyncWrapper<T> { |
170 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { |
171 | f.pad("SyncWrapper" ) |
172 | } |
173 | } |
174 | |
175 | impl<T: Default> Default for SyncWrapper<T> { |
176 | fn default() -> Self { |
177 | Self::new(T::default()) |
178 | } |
179 | } |
180 | |
181 | impl<T> From<T> for SyncWrapper<T> { |
182 | fn from(value: T) -> Self { |
183 | Self::new(value) |
184 | } |
185 | } |
186 | |
187 | /// `Future` which is `Sync`. |
188 | /// |
189 | /// # Examples |
190 | /// |
191 | /// ``` |
192 | /// use sync_wrapper::{SyncWrapper, SyncFuture}; |
193 | /// |
194 | /// let fut = async { 1 }; |
195 | /// let fut = SyncFuture::new(fut); |
196 | /// ``` |
197 | pub struct SyncFuture<F> { |
198 | inner: SyncWrapper<F> |
199 | } |
200 | impl <F: Future> SyncFuture<F> { |
201 | pub fn new(inner: F) -> Self { |
202 | Self { inner: SyncWrapper::new(inner) } |
203 | } |
204 | pub fn into_inner(self) -> F { |
205 | self.inner.into_inner() |
206 | } |
207 | } |
208 | impl <F: Future> Future for SyncFuture<F> { |
209 | type Output = F::Output; |
210 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { |
211 | let inner: Pin<&mut F> = unsafe { self.map_unchecked_mut(|x: &mut SyncFuture| x.inner.get_mut()) }; |
212 | inner.poll(cx) |
213 | } |
214 | } |
215 | |
216 | /// `Stream` which is `Sync`. |
217 | /// |
218 | /// # Examples |
219 | /// |
220 | /// ``` |
221 | /// use sync_wrapper::SyncStream; |
222 | /// use futures::stream; |
223 | /// |
224 | /// let st = stream::iter(vec![1]); |
225 | /// let st = SyncStream::new(st); |
226 | /// ``` |
227 | #[cfg (feature = "futures" )] |
228 | pub struct SyncStream<S> { |
229 | inner: SyncWrapper<S> |
230 | } |
231 | #[cfg (feature = "futures" )] |
232 | impl <S: futures_core::Stream> SyncStream<S> { |
233 | pub fn new(inner: S) -> Self { |
234 | Self { inner: SyncWrapper::new(inner) } |
235 | } |
236 | pub fn into_inner(self) -> S { |
237 | self.inner.into_inner() |
238 | } |
239 | } |
240 | #[cfg (feature = "futures" )] |
241 | impl <S: futures_core::Stream> futures_core::Stream for SyncStream<S> { |
242 | type Item = S::Item; |
243 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { |
244 | let inner = unsafe { self.map_unchecked_mut(|x| x.inner.get_mut()) }; |
245 | inner.poll_next(cx) |
246 | } |
247 | } |
248 | |
249 | |