Skip to content

Commit 750e902

Browse files
authored
Rollup merge of #146675 - Jules-Bertholet:sync-nonexclusive, r=Mark-Simulacrum
Allow shared access to `Exclusive<T>` when `T: Sync` Addresses libs-api request in #98407 (comment). Adds the following trait impls to `Exclusive<T>`, all bounded on `T: Sync`: - `AsRef<T>` - `Clone` - `Copy` - `PartialEq` - `StructuralPartialEq` - `Eq` - `Hash` - `PartialOrd` - `Ord` - `Fn` ``@rustbot`` label T-libs-api
2 parents c29fb2e + f1d6e00 commit 750e902

File tree

4 files changed

+109
-11
lines changed

4 files changed

+109
-11
lines changed

library/core/src/sync/exclusive.rs

Lines changed: 104 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
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
17-
/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API
18-
/// whatsoever, making it useless, thus harmless, thus memory safe.
19+
/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive<T>` for non-`Sync` T
20+
/// has no API whatsoever, making it useless, thus harmless, thus memory safe.
1921
///
2022
/// Certain constructs like [`Future`]s can only be used with _exclusive_ access,
2123
/// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the
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)]
@@ -195,6 +201,17 @@ where
195201
}
196202
}
197203

204+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
205+
impl<F, Args> Fn<Args> for Exclusive<F>
206+
where
207+
F: Sync + Fn<Args>,
208+
Args: Tuple,
209+
{
210+
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
211+
self.as_ref().call(args)
212+
}
213+
}
214+
198215
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
199216
impl<T> Future for Exclusive<T>
200217
where
@@ -221,3 +238,80 @@ where
221238
G::resume(self.get_pin_mut(), arg)
222239
}
223240
}
241+
242+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
243+
impl<T> AsRef<T> for Exclusive<T>
244+
where
245+
T: Sync + ?Sized,
246+
{
247+
#[inline]
248+
fn as_ref(&self) -> &T {
249+
&self.inner
250+
}
251+
}
252+
253+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
254+
impl<T> Clone for Exclusive<T>
255+
where
256+
T: Sync + Clone,
257+
{
258+
#[inline]
259+
fn clone(&self) -> Self {
260+
Self { inner: self.inner.clone() }
261+
}
262+
}
263+
264+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
265+
impl<T> Copy for Exclusive<T> where T: Sync + Copy {}
266+
267+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
268+
impl<T, U> PartialEq<Exclusive<U>> for Exclusive<T>
269+
where
270+
T: Sync + PartialEq<U> + ?Sized,
271+
U: Sync + ?Sized,
272+
{
273+
#[inline]
274+
fn eq(&self, other: &Exclusive<U>) -> bool {
275+
self.inner == other.inner
276+
}
277+
}
278+
279+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
280+
impl<T> StructuralPartialEq for Exclusive<T> where T: Sync + StructuralPartialEq + ?Sized {}
281+
282+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
283+
impl<T> Eq for Exclusive<T> where T: Sync + Eq + ?Sized {}
284+
285+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
286+
impl<T> Hash for Exclusive<T>
287+
where
288+
T: Sync + Hash + ?Sized,
289+
{
290+
#[inline]
291+
fn hash<H: Hasher>(&self, state: &mut H) {
292+
Hash::hash(&self.inner, state)
293+
}
294+
}
295+
296+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
297+
impl<T, U> PartialOrd<Exclusive<U>> for Exclusive<T>
298+
where
299+
T: Sync + PartialOrd<U> + ?Sized,
300+
U: Sync + ?Sized,
301+
{
302+
#[inline]
303+
fn partial_cmp(&self, other: &Exclusive<U>) -> Option<Ordering> {
304+
self.inner.partial_cmp(&other.inner)
305+
}
306+
}
307+
308+
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
309+
impl<T> Ord for Exclusive<T>
310+
where
311+
T: Sync + Ord + ?Sized,
312+
{
313+
#[inline]
314+
fn cmp(&self, other: &Self) -> Ordering {
315+
self.inner.cmp(&other.inner)
316+
}
317+
}

tests/ui/explicit-tail-calls/callee_is_weird.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ error: tail calls can only be performed with function definitions or pointers
1212
LL | become (&mut &std::sync::Exclusive::new(f))()
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414
|
15-
= note: callee has type `Exclusive<fn() {f}>`
15+
= note: callee has type `&Exclusive<fn() {f}>`
1616

1717
error: tail calls can only be performed with function definitions or pointers
1818
--> $DIR/callee_is_weird.rs:22:12

tests/ui/impl-trait/where-allowed.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,8 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani
387387
where A: Tuple, F: Fn<A>, F: ?Sized;
388388
- impl<Args, F, A> Fn<Args> for Box<F, A>
389389
where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
390+
- impl<F, Args> Fn<Args> for Exclusive<F>
391+
where F: Sync, F: Fn<Args>, Args: Tuple;
390392

391393
error[E0118]: no nominal type found for inherent implementation
392394
--> $DIR/where-allowed.rs:240:1

tests/ui/traits/next-solver/well-formed-in-relate.stderr

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ LL | x = unconstrained_map();
1212
where A: Tuple, F: Fn<A>, F: ?Sized;
1313
- impl<Args, F, A> Fn<Args> for Box<F, A>
1414
where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
15+
- impl<F, Args> Fn<Args> for Exclusive<F>
16+
where F: Sync, F: Fn<Args>, Args: Tuple;
1517
note: required by a bound in `unconstrained_map`
1618
--> $DIR/well-formed-in-relate.rs:21:25
1719
|

0 commit comments

Comments
 (0)