Arcs are pointers to some heap allocated ArcInners that contains the strong and weak counters, and the actual data, while Mutexs contain their data directly, but prevent moving their sys::Mutex using a box, so Arc<Mutex<T>> requires two allocations. We could combine them into some faster ArcMutex<T> type with only one allocation, but..
An ArcMutex<T> would work because Arc pins its allocation, so could we instead create a MustPinMutex<T> type that works only when pinned? ArcMutex<T> then becomes Arc<Pin<MustPinMutex<T>>>.
struct MustPinMutex<T: ?Sized> {
inner: sys::Mutex,
// I'd hope `sys::Mutex: !Unpin` but just in case:
notpin: std::marker::PhantomPinned,
poison: poison::Flag,
data: UnsafeCell<T>,
}
We'd have methods on Pin<MustPinMutex<T>> resembling Mutex::*, but almost nothing on MustPinMutex<T> itself.
We cannot currently obtain Pin<&Mutex2<T>> from the Pin<Arc<Mutex2<T>> though. We do obtain &Mutex2<T> via impl<P: Deref> Deref for Pin<P>, but that seems useless. I'd think Arc could provide pin projection however:
Afaik std::sync::Mutex requiring an extra layer of boxing is an implementation detail. You can avoid double boxing by using another Mutex type. As far as I understand parking_lot::Mutex does not require another layer of boxing.
It thereby does what you want to achieve without adding anything new.
pin-project should handle the unsafe code for those x and y methods.
I suppose Mutex2 must be implemented in std since it requires access to sys::Mutex, no? Arc<..Mutex<T>..> happens lots so this should provide significant savings. As an example, futures-timer contains two Mutex inside and Arc.
I suppose Mutex2 could be implemented on nightly outside std using #![feature(arbitrary_self_types)] for lock and try_lock on Pin<&Mutex2<T>>, and #![feature(libstd_sys_internals)] for access to sys::Mutex, yes?