diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index cf086bf4f5080..f181c5514f256 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -1,28 +1,32 @@ //! Defines [`Exclusive`]. +use core::cmp::Ordering; use core::fmt; use core::future::Future; -use core::marker::Tuple; +use core::hash::{Hash, Hasher}; +use core::marker::{StructuralPartialEq, Tuple}; use core::ops::{Coroutine, CoroutineState}; use core::pin::Pin; use core::task::{Context, Poll}; -/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_ -/// access to the underlying value. It provides no _immutable_, or _shared_ -/// access to the underlying value. +/// `Exclusive` provides _mutable_ access, also referred to as _exclusive_ +/// access to the underlying value. However, it only permits _immutable_, or _shared_ +/// access to the underlying value when that value is [`Sync`]. /// /// While this may seem not very useful, it allows `Exclusive` to _unconditionally_ -/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive` +/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `Exclusive` /// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound -/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` has no API -/// whatsoever, making it useless, thus harmless, thus memory safe. +/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` for non-`Sync` T +/// has no API whatsoever, making it useless, thus harmless, thus memory safe. /// /// Certain constructs like [`Future`]s can only be used with _exclusive_ access, /// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the /// Rust compiler that something is `Sync` in practice. /// /// ## Examples -/// Using a non-`Sync` future prevents the wrapping struct from being `Sync` +/// +/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`: +/// /// ```compile_fail /// use core::cell::Cell; /// @@ -43,7 +47,8 @@ use core::task::{Context, Poll}; /// ``` /// /// `Exclusive` ensures the struct is `Sync` without stripping the future of its -/// functionality. +/// functionality: +/// /// ``` /// #![feature(exclusive_wrapper)] /// use core::cell::Cell; @@ -66,6 +71,7 @@ use core::task::{Context, Poll}; /// ``` /// /// ## Parallels with a mutex +/// /// In some sense, `Exclusive` can be thought of as a _compile-time_ version of /// a mutex, as the borrow-checker guarantees that only one `&mut` can exist /// for any value. This is a parallel with the fact that @@ -75,7 +81,7 @@ use core::task::{Context, Poll}; #[doc(alias = "SyncWrapper")] #[doc(alias = "SyncCell")] #[doc(alias = "Unique")] -// `Exclusive` can't have `PartialOrd`, `Clone`, etc. impls as they would +// `Exclusive` can't have derived `PartialOrd`, `Clone`, etc. impls as they would // use `&` access to the inner value, violating the `Sync` impl's safety // requirements. #[derive(Default)] @@ -195,6 +201,17 @@ where } } +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Fn for Exclusive +where + F: Sync + Fn, + Args: Tuple, +{ + extern "rust-call" fn call(&self, args: Args) -> Self::Output { + self.as_ref().call(args) + } +} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Future for Exclusive where @@ -221,3 +238,80 @@ where G::resume(self.get_pin_mut(), arg) } } + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl AsRef for Exclusive +where + T: Sync + ?Sized, +{ + #[inline] + fn as_ref(&self) -> &T { + &self.inner + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Clone for Exclusive +where + T: Sync + Clone, +{ + #[inline] + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Copy for Exclusive where T: Sync + Copy {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl PartialEq> for Exclusive +where + T: Sync + PartialEq + ?Sized, + U: Sync + ?Sized, +{ + #[inline] + fn eq(&self, other: &Exclusive) -> bool { + self.inner == other.inner + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl StructuralPartialEq for Exclusive where T: Sync + StructuralPartialEq + ?Sized {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Eq for Exclusive where T: Sync + Eq + ?Sized {} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Hash for Exclusive +where + T: Sync + Hash + ?Sized, +{ + #[inline] + fn hash(&self, state: &mut H) { + Hash::hash(&self.inner, state) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl PartialOrd> for Exclusive +where + T: Sync + PartialOrd + ?Sized, + U: Sync + ?Sized, +{ + #[inline] + fn partial_cmp(&self, other: &Exclusive) -> Option { + self.inner.partial_cmp(&other.inner) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl Ord for Exclusive +where + T: Sync + Ord + ?Sized, +{ + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.inner.cmp(&other.inner) + } +} diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.stderr b/tests/ui/explicit-tail-calls/callee_is_weird.stderr index a4e5a38ce3320..9a5da28b559e3 100644 --- a/tests/ui/explicit-tail-calls/callee_is_weird.stderr +++ b/tests/ui/explicit-tail-calls/callee_is_weird.stderr @@ -12,7 +12,7 @@ error: tail calls can only be performed with function definitions or pointers LL | become (&mut &std::sync::Exclusive::new(f))() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: callee has type `Exclusive` + = note: callee has type `&Exclusive` error: tail calls can only be performed with function definitions or pointers --> $DIR/callee_is_weird.rs:22:12 diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 08caff326c470..4d8f23bf7ca64 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -387,6 +387,8 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani where A: Tuple, F: Fn, F: ?Sized; - impl Fn for Box where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + - impl Fn for Exclusive + where F: Sync, F: Fn, Args: Tuple; error[E0118]: no nominal type found for inherent implementation --> $DIR/where-allowed.rs:240:1 diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr index 5294a072d3123..d79e465b3e387 100644 --- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -12,6 +12,8 @@ LL | x = unconstrained_map(); where A: Tuple, F: Fn, F: ?Sized; - impl Fn for Box where Args: Tuple, F: Fn, A: Allocator, F: ?Sized; + - impl Fn for Exclusive + where F: Sync, F: Fn, Args: Tuple; note: required by a bound in `unconstrained_map` --> $DIR/well-formed-in-relate.rs:21:25 |