# Interior mutability and shared ownership

Choose between reference counting, runtime borrow checks, and locks.

Canonical: https://rust.robertdevore.com/course/15-interior/
Author: Robert DeVore
Technical baseline: Rust 1.98.1, edition 2024; verified 2026-09-06.

## Shared does not always mean unchanging

Ordinary data behind `&T` cannot be mutated while the shared reference's contract applies. Interior-mutability types let you change data through a shared reference under defined rules. They rely on `UnsafeCell` internally, but each safe abstraction supplies its own rules. `UnsafeCell` itself does not prevent data races or allow competing `&mut` references.


### Run the example

```sh
cargo run --locked --example 15_interior
```

```rust
use std::{cell::RefCell, rc::Rc};
fn main() {
    let data = Rc::new(RefCell::new(vec![1]));
    let other = Rc::clone(&data);
    {
        let mut guard = other.borrow_mut();
        guard.push(2);
        assert!(data.try_borrow().is_err());
    }
    assert_eq!(*data.borrow(), [1, 2]);
    assert_eq!(Rc::strong_count(&data), 2);
}
```

[View the tested source](https://github.com/robertdevore/rust.robertdevore.com/blob/main/examples/15_interior.rs)


`Rc` gives two owning handles to the same allocation. `RefCell` tracks borrows at runtime. While the mutable guard exists, `try_borrow()` reports a conflict. After that guard is dropped, the shared borrow succeeds. Leaving the block drops the guard and ends its borrow.

`borrow()` and `borrow_mut()` panic on a runtime conflict; their `try_` variants return an error. Use the `try_` variants when your program should handle a borrow conflict rather than panic. A runtime check does not mean the compiler has stopped enforcing all safety: the guard types and library implementation cooperate to preserve access rules.

## Pick the narrowest mechanism

`Cell<T>` can replace a value without handing out ordinary references to its interior. `RefCell<T>` supports checked borrows within a thread. `Mutex<T>` coordinates access across threads. `Rc<T>` is not a thread-safe reference counter; `Arc<T>` is, but that does not make every `T` thread-safe. `Arc<RefCell<T>>` is not a substitute for a synchronized mutation abstraction.

Reference-counted cycles can leak memory. Use weak references or redesign ownership where a graph needs back-links. A leak is a resource bug even when it does not violate memory safety. Rust's safety model does not imply every resource is eventually reclaimed.

## Apply this to the course project

The event counter owns its summary and reads records sequentially. It does not need a reference-counted mutable summary. Passing `&mut Summary` to a function already states the intended exclusive update. Add a cell or lock only when a real relationship requires shared access with mutation.

If a compiler error appears because two components both want ownership, first consider transferring ownership at a message boundary. If they only read immutable data, an ordinary borrow or `Arc<T>` may be enough. Each mechanism adds behavior you need to understand and test.

## Exercise

Keep the mutable `RefCell` guard alive and call `try_borrow` from the other handle. Assert failure. Drop the guard explicitly and assert success. Explain why cloning the `Rc` does not create a second vector.

<details><summary>Solution and acceptance check</summary>

The first attempt returns `Err`; the second sees `[1, 2]`. Both handles refer to the same cell and its borrow state. `Rc::clone` increases the owning handle count. To copy the data itself, you would need to clone the vector separately.

</details>

Sources: [`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html), [`UnsafeCell`](https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html), and [`Rc`](https://doc.rust-lang.org/std/rc/).

