Description
Proposal
Problem statement
There is currently no way to check whether an Arc
has unique access to its data that doesn’t involve producing an &mut
to the inner data. However, this is undesirable for some use cases as it invalidates existing pointers to the Arc
.
Motivating examples or use cases
Suppose one has a self-referential data structure consisting of an Arc<T>
and an &T
, though the &T
may also for instance point to static data and not the Arc
, and the goal is to write a function that produces a T
from this data structure. One implementation would be to first check whether if the Arc
is unique and then check if the &T
indeed points to the Arc
, and if so, call Arc::into_inner
, otherwise clone the T
from the reference. However, currently the step of checking if the Arc
is unique will force the &T
to be invalidated, meaning one cannot later clone should the second check fail.
In a simple case one could just reorder the two checks to solve this issue, but this is not always trivial to achieve depending on what abstractions are involved: for example, if there were multiple possible backing Arc
s, one would have to check all of the pointers before attempting to Arc::into_inner
the first, instead of being able to short-circuit should the first succeed. In a more complex case, if the dependent data was not &T
but had a destructor, there would be no way to correctly run it: if the destructor was run before get_mut
or into_inner
, it would be impossible to recover the original data to clone it later, but if it was run after, it would already be invalidated.
Solution sketch
impl<T, A> Arc<T, A> {
pub fn is_unique(&self) -> bool;
}
One argument for the inclusion of this API directly is that, even when lifetime-extended references are not involved, some people might try and, instead of calling Arc::get_mut(&mut arc).is_some()
, call Arc::strong_count(&arc) == 1
– indeed, grep.app displays many results for this pattern – and not be aware of the race condition this may introduce should weak references exist, leading to code that is subtly wrong. Introducing this method makes it more likely that people will choose the correct way of implementing this function.
Alternatives
impl<T, A> Arc<T, A> {
pub fn as_mut_ptr(&mut self) -> Option<*mut T>;
}
This doesn’t come with the discoverability advantages of is_unique
mentioned above. However, it does make it more explicit that one can obtain mutable access to the internal value, which might be convenient. It is currently not guaranteed that one can mutate through the pointer returned by Arc::as_ptr
– there was one attempt to guarantee this that fizzled out – but it is unlikely that we will not end up guaranteeing this.
Another alternative is having the method take &mut self
instead of &self
. This can reduce footguns since is_unique
is rarely useful when used as an &self
method, but it is possibly outweighed by the flexibility.
Links and related work
None I’m aware of.
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.
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.