Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 750e902

Browse files
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)

AltStyle によって変換されたページ (->オリジナル) /