Is there a wrapper type that blocks mut without requiring allocation?

Say I have this type, and it's working fine:

struct Task {
    status: Rc<Mutex<TaskState>>,
    db: DatabaseClient,
    foo: Foo,
    ...
}

In my program, the Task is always the last owner of status and therefore always takes care of cleanup. For performance, I now want to eliminate the reference counting, i.e. remove the Rc and store the Mutex directly inside the Task. Other code can still have short-lived shared references to the Mutex.

Now the problem. The existing code sometimes uses &mut Task. This works fine with Rc because the Rc means that a mut reference to the Task does not imply exclusive access to the Mutex<TaskState>. Mut access isn't transitive through an Rc; the Rc blocks it. But if I remove the Rc, I can't have a &mut Task while other references to the mutex exist.

If I'm reading the UnsafeCell docs correctly, they explicitly say that it doesn't do this ("neither the cell nor the wrapped value may be aliased for the duration of that &mut borrow"). Is there anything in Rust that does, even with unsafe code?

(Of course there are plenty of ways I could do a bigger refactor, maybe take a slight perf hit, and not need this capability. But I'm interested in the capability.)

Oh, never mind. This is impossible because of assignment. If I have t: &mut Task I can always just *t = Task { ... } and clobber everything within.

When there is only a single reference to Rc, it is mutable:

and similarly Mutex can be accessed without locking if you have &mut to it.

If you want to prevent mutation of a field, keeping the field private is the best you can do.

And you will have to deal with mem::replace/mem::swap being able to replace whole objects with their private fields. That's one of the reasons why Pin+!Unpin needs to exists and Box alone doesn't guarantee stable address for its content.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.