Skip to main content

core/sync/
sync_view.rs

1//! Defines [`SyncView`].
2
3use core::clone::TrivialClone;
4use core::cmp::Ordering;
5use core::fmt;
6use core::future::Future;
7use core::hash::{Hash, Hasher};
8use core::marker::{StructuralPartialEq, Tuple};
9use core::ops::{Coroutine, CoroutineState};
10use core::pin::Pin;
11use core::task::{Context, Poll};
12
13/// `SyncView` provides _mutable_ access, also referred to as _exclusive_
14/// access to the underlying value. However, it only permits _immutable_, or _shared_
15/// access to the underlying value when that value is [`Sync`].
16///
17/// While this may seem not very useful, it allows `SyncView` to _unconditionally_
18/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `SyncView`
19/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound
20/// for `&SyncView` to cross thread boundaries. By design, a `&SyncView<T>` for non-`Sync`
21/// `T` has no API whatsoever, making it useless, thus harmless, thus memory safe.
22///
23/// Certain constructs like [`Future`]s can only be used with _exclusive_ access,
24/// and are often [`Send`] but not `Sync`, so `SyncView` can be used as hint to the
25/// Rust compiler that something is `Sync` in practice.
26///
27/// ## Examples
28///
29/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`:
30///
31/// ```compile_fail
32/// use core::cell::Cell;
33///
34/// async fn other() {}
35/// fn assert_sync<T: Sync>(t: T) {}
36/// struct State<F> {
37///     future: F
38/// }
39///
40/// assert_sync(State {
41///     future: async {
42///         let cell = Cell::new(1);
43///         let cell_ref = &cell;
44///         other().await;
45///         let value = cell_ref.get();
46///     }
47/// });
48/// ```
49///
50/// `SyncView` ensures the struct is `Sync` without stripping the future of its
51/// functionality:
52///
53/// ```
54/// #![feature(exclusive_wrapper)]
55/// use core::cell::Cell;
56/// use core::sync::SyncView;
57///
58/// async fn other() {}
59/// fn assert_sync<T: Sync>(t: T) {}
60/// struct State<F> {
61///     future: SyncView<F>
62/// }
63///
64/// assert_sync(State {
65///     future: SyncView::new(async {
66///         let cell = Cell::new(1);
67///         let cell_ref = &cell;
68///         other().await;
69///         let value = cell_ref.get();
70///     })
71/// });
72/// ```
73///
74/// ## Parallels with a mutex
75///
76/// In some sense, `SyncView` can be thought of as a _compile-time_ version of
77/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist
78/// for any value. This is a parallel with the fact that
79/// `&` and `&mut` references together can be thought of as a _compile-time_
80/// version of a read-write lock.
81#[unstable(feature = "exclusive_wrapper", issue = "98407")]
82#[doc(alias = "SyncWrapper")]
83#[doc(alias = "SyncCell")]
84#[doc(alias = "Unique")]
85#[doc(alias = "Exclusive")]
86// `SyncView` can't have derived `PartialOrd`, `Clone`, etc. impls as they would
87// use `&` access to the inner value, violating the `Sync` impl's safety
88// requirements.
89#[repr(transparent)]
90pub struct SyncView<T: ?Sized> {
91    inner: T,
92}
93
94// See `SyncView`'s docs for justification.
95#[unstable(feature = "exclusive_wrapper", issue = "98407")]
96unsafe impl<T: ?Sized> Sync for SyncView<T> {}
97
98#[unstable(feature = "exclusive_wrapper", issue = "98407")]
99#[rustc_const_unstable(feature = "const_default", issue = "143894")]
100impl<T> const Default for SyncView<T>
101where
102    T: [const] Default,
103{
104    #[inline]
105    fn default() -> Self {
106        Self { inner: Default::default() }
107    }
108}
109
110#[unstable(feature = "exclusive_wrapper", issue = "98407")]
111impl<T: ?Sized> fmt::Debug for SyncView<T> {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
113        f.debug_struct("SyncView").finish_non_exhaustive()
114    }
115}
116
117impl<T: Sized> SyncView<T> {
118    /// Wrap a value in an `SyncView`
119    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
120    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
121    #[must_use]
122    #[inline]
123    pub const fn new(t: T) -> Self {
124        Self { inner: t }
125    }
126
127    /// Unwrap the value contained in the `SyncView`
128    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
129    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
130    #[must_use]
131    #[inline]
132    pub const fn into_inner(self) -> T {
133        self.inner
134    }
135}
136
137impl<T: ?Sized> SyncView<T> {
138    /// Gets pinned exclusive access to the underlying value.
139    ///
140    /// `SyncView` is considered to _structurally pin_ the underlying
141    /// value, which means _unpinned_ `SyncView`s can produce _unpinned_
142    /// access to the underlying value, but _pinned_ `SyncView`s only
143    /// produce _pinned_ access to the underlying value.
144    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
145    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
146    #[must_use]
147    #[inline]
148    pub const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
149        // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned
150        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
151        unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) }
152    }
153
154    /// Build a _mutable_ reference to an `SyncView<T>` from
155    /// a _mutable_ reference to a `T`. This allows you to skip
156    /// building an `SyncView` with [`SyncView::new`].
157    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
158    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
159    #[must_use]
160    #[inline]
161    pub const fn from_mut(r: &'_ mut T) -> &'_ mut SyncView<T> {
162        // SAFETY: repr is ≥ C, so refs have the same layout; and `SyncView` properties are `&mut`-agnostic
163        unsafe { &mut *(r as *mut T as *mut SyncView<T>) }
164    }
165
166    /// Build a _pinned mutable_ reference to an `SyncView<T>` from
167    /// a _pinned mutable_ reference to a `T`. This allows you to skip
168    /// building an `SyncView` with [`SyncView::new`].
169    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
170    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
171    #[must_use]
172    #[inline]
173    pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut SyncView<T>> {
174        // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned
175        // `Pin::map_unchecked_mut` is not const, so we do this conversion manually
176        unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) }
177    }
178}
179
180impl<T: ?Sized + Sync> SyncView<T> {
181    /// Gets pinned shared access to the underlying value.
182    ///
183    /// `SyncView` is considered to _structurally pin_ the underlying
184    /// value, which means _unpinned_ `SyncView`s can produce _unpinned_
185    /// access to the underlying value, but _pinned_ `SyncView`s only
186    /// produce _pinned_ access to the underlying value.
187    #[unstable(feature = "exclusive_wrapper", issue = "98407")]
188    #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")]
189    #[must_use]
190    #[inline]
191    pub const fn as_pin(self: Pin<&Self>) -> Pin<&T> {
192        // SAFETY: `SyncView` can only produce `&T` if itself is unpinned
193        // `Pin::map_unchecked` is not const, so we do this conversion manually
194        unsafe { Pin::new_unchecked(&self.get_ref().inner) }
195    }
196}
197
198#[unstable(feature = "exclusive_wrapper", issue = "98407")]
199#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
200impl<T> const From<T> for SyncView<T> {
201    #[inline]
202    fn from(t: T) -> Self {
203        Self::new(t)
204    }
205}
206
207#[unstable(feature = "exclusive_wrapper", issue = "98407")]
208#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
209impl<F, Args> const FnOnce<Args> for SyncView<F>
210where
211    F: [const] FnOnce<Args>,
212    Args: Tuple,
213{
214    type Output = F::Output;
215
216    extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
217        self.into_inner().call_once(args)
218    }
219}
220
221#[unstable(feature = "exclusive_wrapper", issue = "98407")]
222#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
223impl<F, Args> const FnMut<Args> for SyncView<F>
224where
225    F: [const] FnMut<Args>,
226    Args: Tuple,
227{
228    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
229        self.as_mut().call_mut(args)
230    }
231}
232
233#[unstable(feature = "exclusive_wrapper", issue = "98407")]
234#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")]
235impl<F, Args> const Fn<Args> for SyncView<F>
236where
237    F: Sync + [const] Fn<Args>,
238    Args: Tuple,
239{
240    extern "rust-call" fn call(&self, args: Args) -> Self::Output {
241        self.as_ref().call(args)
242    }
243}
244
245#[unstable(feature = "exclusive_wrapper", issue = "98407")]
246impl<F, Args> AsyncFnOnce<Args> for SyncView<F>
247where
248    F: AsyncFnOnce<Args>,
249    Args: Tuple,
250{
251    type CallOnceFuture = F::CallOnceFuture;
252
253    type Output = F::Output;
254
255    extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture {
256        self.into_inner().async_call_once(args)
257    }
258}
259
260#[unstable(feature = "exclusive_wrapper", issue = "98407")]
261impl<F, Args> AsyncFnMut<Args> for SyncView<F>
262where
263    F: AsyncFnMut<Args>,
264    Args: Tuple,
265{
266    type CallRefFuture<'a>
267        = F::CallRefFuture<'a>
268    where
269        F: 'a;
270
271    extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> {
272        self.as_mut().async_call_mut(args)
273    }
274}
275
276#[unstable(feature = "exclusive_wrapper", issue = "98407")]
277impl<F, Args> AsyncFn<Args> for SyncView<F>
278where
279    F: Sync + AsyncFn<Args>,
280    Args: Tuple,
281{
282    extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> {
283        self.as_ref().async_call(args)
284    }
285}
286
287#[unstable(feature = "exclusive_wrapper", issue = "98407")]
288impl<T> Future for SyncView<T>
289where
290    T: Future + ?Sized,
291{
292    type Output = T::Output;
293
294    #[inline]
295    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
296        self.as_pin_mut().poll(cx)
297    }
298}
299
300#[unstable(feature = "coroutine_trait", issue = "43122")] // also #98407
301impl<R, G> Coroutine<R> for SyncView<G>
302where
303    G: Coroutine<R> + ?Sized,
304{
305    type Yield = G::Yield;
306    type Return = G::Return;
307
308    #[inline]
309    fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
310        G::resume(self.as_pin_mut(), arg)
311    }
312}
313
314#[unstable(feature = "exclusive_wrapper", issue = "98407")]
315#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
316impl<T> const AsRef<T> for SyncView<T>
317where
318    T: Sync + ?Sized,
319{
320    /// Gets shared access to the underlying value.
321    #[inline]
322    fn as_ref(&self) -> &T {
323        &self.inner
324    }
325}
326
327#[unstable(feature = "exclusive_wrapper", issue = "98407")]
328#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
329impl<T> const AsMut<T> for SyncView<T>
330where
331    T: ?Sized,
332{
333    /// Gets exclusive access to the underlying value.
334    #[inline]
335    fn as_mut(&mut self) -> &mut T {
336        &mut self.inner
337    }
338}
339
340#[unstable(feature = "exclusive_wrapper", issue = "98407")]
341#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
342impl<T> const Clone for SyncView<T>
343where
344    T: Sync + [const] Clone,
345{
346    #[inline]
347    fn clone(&self) -> Self {
348        Self { inner: self.inner.clone() }
349    }
350}
351
352#[doc(hidden)]
353#[unstable(feature = "trivial_clone", issue = "none")]
354#[rustc_const_unstable(feature = "const_clone", issue = "142757")]
355unsafe impl<T> const TrivialClone for SyncView<T> where T: Sync + [const] TrivialClone {}
356
357#[unstable(feature = "exclusive_wrapper", issue = "98407")]
358impl<T> Copy for SyncView<T> where T: Sync + Copy {}
359
360#[unstable(feature = "exclusive_wrapper", issue = "98407")]
361#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
362impl<T, U> const PartialEq<SyncView<U>> for SyncView<T>
363where
364    T: Sync + [const] PartialEq<U> + ?Sized,
365    U: Sync + ?Sized,
366{
367    #[inline]
368    fn eq(&self, other: &SyncView<U>) -> bool {
369        self.inner == other.inner
370    }
371}
372
373#[unstable(feature = "exclusive_wrapper", issue = "98407")]
374impl<T> StructuralPartialEq for SyncView<T> where T: Sync + StructuralPartialEq + ?Sized {}
375
376#[unstable(feature = "exclusive_wrapper", issue = "98407")]
377#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
378impl<T> const Eq for SyncView<T> where T: Sync + [const] Eq + ?Sized {}
379
380#[unstable(feature = "exclusive_wrapper", issue = "98407")]
381impl<T> Hash for SyncView<T>
382where
383    T: Sync + Hash + ?Sized,
384{
385    #[inline]
386    fn hash<H: Hasher>(&self, state: &mut H) {
387        Hash::hash(&self.inner, state)
388    }
389}
390
391#[unstable(feature = "exclusive_wrapper", issue = "98407")]
392#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
393impl<T, U> const PartialOrd<SyncView<U>> for SyncView<T>
394where
395    T: Sync + [const] PartialOrd<U> + ?Sized,
396    U: Sync + ?Sized,
397{
398    #[inline]
399    fn partial_cmp(&self, other: &SyncView<U>) -> Option<Ordering> {
400        self.inner.partial_cmp(&other.inner)
401    }
402}
403
404#[unstable(feature = "exclusive_wrapper", issue = "98407")]
405#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
406impl<T> const Ord for SyncView<T>
407where
408    T: Sync + [const] Ord + ?Sized,
409{
410    #[inline]
411    fn cmp(&self, other: &Self) -> Ordering {
412        self.inner.cmp(&other.inner)
413    }
414}