Skip to content

Commit 113a869

Browse files
Allow shared access to Exclusive<T> when T: Sync
1 parent 2ebb126 commit 113a869

File tree

1 file changed

+89
-8
lines changed

1 file changed

+89
-8
lines changed

library/core/src/sync/exclusive.rs

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
//! Defines [`Exclusive`].
22
3+
use core::cmp::Ordering;
34
use core::fmt;
45
use core::future::Future;
5-
use core::marker::Tuple;
6+
use core::hash::{Hash, Hasher};
7+
use core::marker::{StructuralPartialEq, Tuple};
68
use core::ops::{Coroutine, CoroutineState};
79
use core::pin::Pin;
810
use core::task::{Context, Poll};
911

10-
/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_
11-
/// access to the underlying value. It provides no _immutable_, or _shared_
12-
/// access to the underlying value.
12+
/// `Exclusive` provides _mutable_ access, also referred to as _exclusive_
13+
/// access to the underlying value. However, it only permits _immutable_, or _shared_
14+
/// access to the underlying value when that value is [`Sync`].
1315
///
1416
/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_
15-
/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive`
17+
/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `Exclusive`
1618
/// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound
1719
/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API
1820
/// whatsoever, making it useless, thus harmless, thus memory safe.
@@ -22,7 +24,9 @@ use core::task::{Context, Poll};
2224
/// Rust compiler that something is `Sync` in practice.
2325
///
2426
/// ## Examples
25-
/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`
27+
///
28+
/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`:
29+
///
2630
/// ```compile_fail
2731
/// use core::cell::Cell;
2832
///
@@ -43,7 +47,8 @@ use core::task::{Context, Poll};
4347
/// ```
4448
///
4549
/// `Exclusive` ensures the struct is `Sync` without stripping the future of its
46-
/// functionality.
50+
/// functionality:
51+
///
4752
/// ```
4853
/// #![feature(exclusive_wrapper)]
4954
/// use core::cell::Cell;
@@ -66,6 +71,7 @@ use core::task::{Context, Poll};
6671
/// ```
6772
///
6873
/// ## Parallels with a mutex
74+
///
6975
/// In some sense, `Exclusive` can be thought of as a _compile-time_ version of
7076
/// a mutex, as the borrow-checker guarantees that only one `&mut` can exist
7177
/// for any value. This is a parallel with the fact that
@@ -75,7 +81,7 @@ use core::task::{Context, Poll};
7581
#[doc(alias = "SyncWrapper")]
7682
#[doc(alias = "SyncCell")]
7783
#[doc(alias = "Unique")]
78-
// `Exclusive` can't have `PartialOrd`, `Clone`, etc. impls as they would
84+
// `Exclusive` can't have derived `PartialOrd`, `Clone`, etc. impls as they would
7985
// use `&` access to the inner value, violating the `Sync` impl's safety
8086
// requirements.
8187
#[derive(Default)]
@@ -221,3 +227,78 @@ where
221227
G::resume(self.get_pin_mut(), arg)
222228
}
223229
}
230+
231+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
232+
impl<T> AsRef<T> for Exclusive<T>
233+
where
234+
T: Sync + ?Sized,
235+
{
236+
#[inline]
237+
fn as_ref(&self) -> &T {
238+
&self.inner
239+
}
240+
}
241+
242+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
243+
impl<T> Clone for Exclusive<T>
244+
where
245+
T: Sync + Clone,
246+
{
247+
#[inline]
248+
fn clone(&self) -> Self {
249+
Self { inner: self.inner.clone() }
250+
}
251+
}
252+
253+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
254+
impl<T> Copy for Exclusive<T> where T: Sync + Copy {}
255+
256+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
257+
impl<T> PartialEq for Exclusive<T>
258+
where
259+
T: Sync + PartialEq + ?Sized,
260+
{
261+
#[inline]
262+
fn eq(&self, other: &Self) -> bool {
263+
self.inner == other.inner
264+
}
265+
}
266+
267+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
268+
impl<T> StructuralPartialEq for Exclusive<T> where T: Sync + StructuralPartialEq + ?Sized {}
269+
270+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
271+
impl<T> Eq for Exclusive<T> where T: Sync + Eq + ?Sized {}
272+
273+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
274+
impl<T> Hash for Exclusive<T>
275+
where
276+
T: Sync + Hash + ?Sized,
277+
{
278+
#[inline]
279+
fn hash<H: Hasher>(&self, state: &mut H) {
280+
Hash::hash(&self.inner, state)
281+
}
282+
}
283+
284+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
285+
impl<T> PartialOrd for Exclusive<T>
286+
where
287+
T: Sync + PartialOrd + ?Sized,
288+
{
289+
#[inline]
290+
fn partial_cmp(&self, other: &Exclusive<T>) -> Option<Ordering> {
291+
self.inner.partial_cmp(&other.inner)
292+
}
293+
}
294+
295+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
296+
impl<T> Ord for Exclusive<T>
297+
where
298+
T: Sync + Ord + ?Sized,
299+
{
300+
#[inline]
301+
fn cmp(&self, other: &Self) -> Ordering {
302+
self.inner.cmp(&other.inner)
303+
}
304+
}

0 commit comments

Comments
 (0)