unchecked_wrap
This crate provides the UncheckedSync<T>, UncheckedSend<T>, and
UncheckedSyncSend<T> types. They are transparent wrappers around T, except
that they unconditionally implement Sync, Send, or both Sync and Send,
respectively. They can be used for, e.g., a static mut replacement, sending
pointers over thread boundaries, storing raw pointers in thread-safe
abstractions, etc.
Constructing these wrappers is unsafe. However, the Unchecked wrapper types
implement Deref and DerefMut, making them mostly usable as if they're just
plain values of type T.
UncheckedSync<T>, UncheckedSend<T>, and UncheckedSyncSend<T> are all
guaranteed to have the same size, alignment, and ABI as T.
Examples
A static mut replacement
Generally, global mutable state should be avoided. However, sometimes it is the right tool. This crate makes this usage pattern more convenient.
// SAFETY: This doctest is single-threaded.
unsafe
Sending a raw pointer across thread boundaries
use UncheckedSend;
let x = 123;
// Suppose that there's some reason that needs to be a raw pointer.
// SAFETY: A raw pointer doesn't actually have thread-safety invariants.
let ptr = unsafe ;
scope;
Storing a raw pointer in a thread-safe abstraction
use PhantomData;
use NonNull;
use UncheckedSyncSend;
// No need for error-prone implementations of Send and Sync.
let a_box = new;
let join_handle = spawn;
join_handle.join.unwrap;
A note on trait implementations
UncheckedSync, UncheckedSend, and UncheckedSyncSend do not implement
common traits such as Debug or Hash
This is because, if, for example, UncheckedSync<T> were to implement Debug
by forwarding to the Debug implementation of the T inside, and if a struct
were to store an UncheckedSync/UncheckedSend, and a #[derive(Debug)] were
to be applied to the struct, then the automatically-generated Debug impl might
read the T value inside in a way that violates thread-safety. (There was
previously an unsoundness in std due to a similar issue with
ManuallyDrop.) In order to avoid this footgun, the Unchecked
wrappers do not implement such traits at all.
However, UncheckedSync<T>, UncheckedSend<T>, and UncheckedSyncSend<T> each
implement Copy when T: Copy. This is to facilitate storing raw pointers in
contexts where they are known to be thread-safe, and then easily copy them
around. I believe that Copy is unlikely to be a footgun in the aforementioned
way.