# Proposal
## Problem statement
This proposes a generalization of the exis…ting unstable API `SyncUnsafeCell`. The `SyncUnsafeCell` type – as far as I understand from the [PR](https://github.com/rust-lang/rust/pull/95438) that adds it – serves (at least) two purposes:
* allow to be a replacement for `static mut`
* simplify implementation of synchronization primitives, because explicit `Send` or `Sync` implementations could be skipped.
The motivation for skipping explicit `Send` or `Sync` implementations isn’t fully explained. However my take on this is that it allows to reduce verbosity, and maybe even to increase accuracy, lowering the chance to mess up manual `Send` or `Sync` implementations: For instance, if you are implementing a synchronization primitive that closely mirrors another existing one in terms of its API – say, a custom `Mutex` re-implementation – then you could simply use `SyncUnsafeCell<T>`, together with a `PhantomData<Mutex<T>>` and then be confident that you got the right `Send` and `Sync` implementation to inherit from `std`’s `Mutex`. (This example also doesn’t fully work with `SyncUnsafeCell<T>` because unlike a `Mutex`, `SyncUnsafeCell<T>: Sync` requires `T: Sync`, something that makes it [not a full `static mut` replacement](https://internals.rust-lang.org/t/pre-rfc-deprecate-then-remove-static-mut/20072/56?u=steffahn), anyways, but that’s a discussion separate from this proposal which *can* support either of keeping or dropping this `T: Sync` restriction.)
My observation now is: There is another type in the standard library that comes with a conservative, but non necessary for soundness, implementation of `!Send` and `!Sync`: Raw pointers. And there, too, it’s very common one has to re-write `Send` and `Sync` implementations manually, even when the type very closely resembles another existing one.
Just to give one example: The type `std::slice::Iter`
```rs
pub struct Iter<'a, T: 'a> {
ptr: NonNull<T>,
end_or_len: *const T,
_marker: PhantomData<&'a T>,
}
```
which even contains a `PhantomData` marker already, where it could simply inherit `Send` and `Sync` implementations from `&'a T`, **needs to verbosely (and with a chance of typo / mistake), feature some manual `unsafe impl Send` and `unsafe impl Sync` implementations mirroring the ones from `&'a T`**.
There likely countless other use cases of pointers used in ways where the pointer is “almost like a reference” in most ways including thread safety, and coming with an accompanying `PhantomData` (taking care of the lifetime). For example if one uses a pointer only because the data is not aligned properly, or to opt out of strict aliasing requirements as in [`aliasable::boxed::AliasableBox`](https://docs.rs/aliasable/0.1.3/aliasable/boxed/struct.AliasableBox.html).
Instead of offering a full copy of `UnsafeCell`’s API called `SyncUnsafeCell` without the conservative `!Sync` restriction, ***and then*** addressing the above analogous problems for pointers, too, by mirroring their full API in hypothetical things like `SyncConstPtr<T>`, `SyncMutPtr<T>`, `SyncNonNull<T>`, we can introduce a single unified way (API) for lifting instance of types with a “lint-like `!Sync` and `!Send` implementation”, quite similar to the “lint-like” nature of `!UnwindSafe` being lifted by `AssertUnwindSafe`, I’m using the name `AssertThreadSafe` here.
## Motivating examples or use cases
To take the above example of `slice::Iter`, that could then look like
```rs
pub struct Iter<'a, T: 'a> {
ptr: AssertThreadSafe<NonNull<T>>,
end_or_len: AssertThreadSafe<*const T>,
_marker: PhantomData<&'a T>,
}
```
and needs no additional `Send` or `Sync` implementation anymore.
Existing `SyncUnsafeCell<T>` is replaced by `AssertThreadSafe<UnsafeCell<T>>`.
## Solution sketch
A minimal / starting point of such an API looks as follows
```rs
use core::ptr::NonNull;
use core::cell::UnsafeCell;
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct AssertThreadSafe<T>(pub T);
unsafe impl<T> Send for AssertThreadSafe<*const T> {}
unsafe impl<T> Send for AssertThreadSafe<*mut T> {}
unsafe impl<T> Send for AssertThreadSafe<NonNull<T>> {}
// UnsafeCell has safe API that makes it usable by mutable reference or owned
// access; so the `T: Send` bound is still necessary, and `AssertThreadSafe<UnsafeCell<T>>`
// only lifts the restrictions on the `Sync` implementation.
unsafe impl<T: Send> Send for AssertThreadSafe<UnsafeCell<T>> {}
unsafe impl<T> Sync for AssertThreadSafe<*const T> {}
unsafe impl<T> Sync for AssertThreadSafe<*mut T> {}
unsafe impl<T> Sync for AssertThreadSafe<NonNull<T>> {}
unsafe impl<T> Sync for AssertThreadSafe<UnsafeCell<T>> {}
```
This particular approach also gives some ``cross-crate traits with a default impl, like `Send`, should not be specialized`` warnings, so I’m not sure whether or not this needs some additional (`!Send` + `!Sync`) marker field to reduce the `Send` and `Sync` implementations to *just* the listed ones.
Alternatively, there’s the option to make this (eventually) extensible, usable even for other crates that may feature some conservatively-`!Sync` types, too. The trait names are placeholders, but the idea would look like this:
```rs
use core::ptr::NonNull;
use core::cell::UnsafeCell;
/// Trait for types that (generally) don't implement Send,
/// but do so only as a precaution. The standard library types `*const T`
/// and `*mut T` are typical examples.
///
/// The types `*const T` and `*mut T` can soundly implement `Send`, even though they don't enforce
/// thread safety, because all API usage that could result in producing data races when the type
/// is sent between threads is already `unsafe`, anyway.
///
/// # Safety
/// This trait may only be implemented for types that can soundly implement `Send`.
/// This is also allowed to be implemented for types that *already do* implement `Send`.
pub unsafe trait SendIsNotUnsound {}
unsafe impl<T> SendIsNotUnsound for *const T {}
unsafe impl<T> SendIsNotUnsound for *mut T {}
unsafe impl<T> SendIsNotUnsound for NonNull<T> {}
// UnsafeCell has safe API that makes it usable by mutable reference or owned
// access; so the `T: Send` bound is still necessary, and `AssertThreadSafe<UnsafeCell<T>>`
// only lifts the restrictions on the `Sync` implementation.
unsafe impl<T: Send> SendIsNotUnsound for UnsafeCell<T> {}
/// Trait for types that (generally) don't implement Sync,
/// but do so only as a precaution. The standard library types `*const T`,
/// `*mut T`, and `UnsafeCell<T>` are typical examples.
///
/// The types `*const T`, `*mut T`, and `UnsafeCell<T>` can soundly implement `Sync`, even though they don't enforce
/// thread safety, because all API usage that could result in producing data races when the type
/// is shared immutably between threads is already `unsafe`, anyway.
///
/// # Safety
/// This trait may only be implemented for types that can soundly implement `Sync`.
/// This is also allowed to be implemented for types that *already do* implement `Sync`.
pub unsafe trait SyncIsNotUnsound {}
unsafe impl<T> SyncIsNotUnsound for *const T {}
unsafe impl<T> SyncIsNotUnsound for *mut T {}
unsafe impl<T> SyncIsNotUnsound for NonNull<T> {}
unsafe impl<T> SyncIsNotUnsound for UnsafeCell<T> {}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct AssertThreadSafe<T>(pub T);
unsafe impl<T: SendIsNotUnsound> Send for AssertThreadSafe<T> {}
unsafe impl<T: SyncIsNotUnsound> Sync for AssertThreadSafe<T> {}
```
One could also support additional types from `std`. For example `Option<NonNull<T>>` comes to mind, because `AssertThreadSafe<Option<NonNull<T>>>` would be easier to work with perhaps than `Option<AssertThreadSafe<NonNull<T>>>`.
```rs
unsafe impl<T> SendIsNotUnsound for Option<NonNull<T>> {}
unsafe impl<T> SyncIsNotUnsound for Option<NonNull<T>> {}
```
To that end, this kind if `impl` could even be further generalized, at least in principle.
```rs
unsafe impl<T: SendIsNotUnsound> SendIsNotUnsound for Option<T> {}
unsafe impl<T: SyncIsNotUnsound> SyncIsNotUnsound for Option<T> {}
```
though it’s hard to say where to stop, and also this all can be happening subsequently, anyways.
Beyond the above `#[derive(Debug, Copy, Clone)]`, `AssertThreadSafe` could implement other traits, too. In particular `Default`. Furthermore, `Deref`/`DerefMut` (pointing to the wrapped type, similar to how `ManuallyDrop` does it) would also be an option. The field of `AssertThreadSafe` could also be private instead of public, and/or named.
## Alternatives
Removing or keeping `SyncUnsafeCell` as-is is the alternatives regarding `UnsafeCell`. For pointer types: As already mentioned in the “Problem Statement” section, one could also offer non-`!Sync`/`!Send` pointer types via a dedicated API, such as individual types `SyncConstPtr<T>`, `SyncMutPtr<T>`, `SyncNonNull<T>`, or a wrapper *only* for the pointer types. But if those *would* be introduced in the future, we definitely need to compare the option of multiple separate types, or a smaller-scope wrapper type, to the unified API from this ACP.
Or we can decide non-`!Sync`/`!Send` pointer types will never be wanted enough, suggest relying on the crate ecosystem for anyone that may find use in it, in which case, for `UnsafeCell` alone, a generalized wrapper like this may be overkill.
<!--
Please also discuss alternative solutions to the problem. Include any reasoning for why you didn't suggest those as the primary solution.
Could this be written using existing APIs? If so, roughly what would that look like? Why does it need to be different? Could this be done as a crate on crates.io?
-->
## Links and related work
Existing discussions on `SyncUnsafeCell` should be relevant, I don’t have a full overview of the most important ones at hand; I can update this section if anything relevant/related gets suggested.
I’ve read https://github.com/rust-lang/rust/issues/53639#issuecomment-634936393
and the answer https://github.com/rust-lang/rust/issues/53639#issuecomment-635009243
where a hypothetical wrapper type came up being called `UnsafeSync<UnsafeCell<T>> `, and my proposal is partially inspired by that, even though I’m not sure what API (and most likely something different from this) was envisioned for “`UnsafeSync`” in that comment. Also the observation in the answer that
> > On names, two alternative possibilities to evaluate would be something like `UnsafeSync<UnsafeCell<T>>` / `UnsafeCell<UnsafeSync<T>>` and something with a new defaulted type parameter like `UnsafeCell<T, Sync>`.
>
> For `UnsafeSync` separated from `UnsafeCell` to be useful it would have to be `Sync` unconditionally, but with a "dual-purpose" `SyncUnsafeCell` type we can have `impl Sync for SyncUnsafeCell<T> where T: Sync` with a bound. Now that I’ve typed this out I’m not sure which is preferable.
doesn’t apply here, because `AssertThreadSafe<UnsafeCell<T>>` *can* support requiring `T: Sync` for `Self: Sync`, just as it does (and *has to* do to stay sound) for `Send`. As mentioned above, I’m questioning whether that `T: Sync` is even wanted, but it works either way. (Just not *both* ways, in case we wanted *both* versions for some reason.[^1]) ([Here](https://github.com/rust-lang/rust/issues/95439#issuecomment-1423330558) the idea to distinguish `SyncUnsafeCell` from a different `AlwaysSyncCell` *is* mentioned, for instance.)
[^1]: Or maybe it *can* even work both ways, dropping the `T: Sync` requirement only once `AssertThreadSafe<AssertThreadSafe<UnsafeCell<T>>>` is used to *really* emphasize all thread-safety that can safely be dropped will be dropped.
## What happens now?
This issue contains an API change proposal (or ACP) and is part of the libs-api team [feature lifecycle]. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
[feature lifecycle]: https://std-dev-guide.rust-lang.org/development/feature-lifecycle.html
## Possible responses
The libs team may respond in various different ways. First, the team will consider the *problem* (this doesn't require any concrete solution or alternatives to have been proposed):
- We think this problem seems worth solving, and the standard library might be the right place to solve it.
- We think that this probably doesn't belong in the standard library.
Second, if there's a concrete solution:
- We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
- We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.