I have recently opened an ACP and am looking for feedback on the idea and the proposed API.
The rough idea is to introduce two new types - ArcRef and ArcMut (aliases of MappedArc and MappedUniqueArc from the ACP, respectively) - which allow one to share subfields of an object owned by an Arc or UniqueArc concurrently.
That is, a UniqueArc will have a map_split method that, like its Rc counterpart, splits the ownership of the underlying object into two (yielding ArcMuts) while keeping the allocation alive as long as at least one strong (subfield) pointer exists.
Similarly, Arc may be split and mapped into ArcRefs, though, unlike UniqueArc, these operations have no limitations.
An ArcMut may not be cloned, but it can be converted into an ArcRef which does implement Clone, at the cost of losing mutable access to the subfield.
Ownership of the whole object may be re-acquired from a shared subfield pointer (ArcRef) if no strong unique (subfield) pointer exists.
An ArcMut can also be turned into a UniqueArc if no strong shared (subfield) pointers exist.
Under this framework, Weak pointers may be promoted to Arc only if there are no unique (subfield) pointers and there is at least one shared (subfield) pointer.
Because a thread can observe changes made to the underlying object by another thread via a unique (subfield) pointer, acquisition of full ownership must take poisoning into account (for instance, a method ArcRef::into_arc should return a LockResult<Option<Arc>>).
You are describing a solution. But what is the problem you are tying to solve? What are the real world use cases that aren't served by existing API in std?
Say you have a complex structure and you want to modify multiple fields at once, for performance reasons. Without scoped threads it is impossible to achieve safely - you either need to make the struct internally mutable or do some unsafe pointer shenanigans.
Another example: you need to perform a calculation that requires a buffer many times in multiple threads. If scoped threads are a no-go, the only thing you can do is allocate a buffer in every thread every time you need to perform this calculation.
With the proposed API one can allocate a large buffer in advance and pass pointers to subslices to the threads without the fear of them getting spontaneously deallocated.
My first question would be whether this impacts the Rust memory layout rules: not all CPU architectures allow atomically changing e.g. a byte at all alignments, there may be some padding needed between fields that is not required when access to the fields is guaranteed to be performed by the same thread.
There is no need for atomic operations on the fields themselves - the uniqueness of the pointers is guaranteed via ref counting and aliasing cannot occur
That is correct, but there may be incidental aliasing of some neighboring bytes if the CPU will first load a whole word and then rewrite it for updating a single byte. There may be specific load and store variants in the instruction set for avoiding this issue but those are not normally needed for the referenced data type, let's call it T, which means that your proposed ArcMut usage taints all writes to &mut T so that these special instructions need to be used.
I may of course be wrong in the sense that the Rust memory layout rules already avoid this issue for other reasons, in which case I'd be delighted to learn more.
If that were a problem, it would also be a problem for scoped threads and slice::split_at_mut. So this can’t make things worse. (I suspect that means “Rust does not support platforms that do not natively support single-byte stores”.)