💾 Archived View for carnage.edvinbasil.com › knowledge › pl › rust › refcell.md captured on 2021-12-17 at 13:26:06. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2020-11-07)

-=-=-=-=-=-=-

RefCell

[Reference Video](https://youtu.be/8O0Nt9qY_vo?t=2482) | [Rust Docs](https://doc.rust-lang.org/std/cell/struct.RefCell.html)

- Unlike other types where the borrow checking is done at compile time, RefCell

allows us to check whether anyone else is mutating at run time

- In essence, it allows safe dynamic borrowing

- Useful in cases where data is not known at compile time: traversal of graphs

and trees

- Refcell is also implemented using `UnsafeCell`

- The structure has a way to keep track of how a value is borrowed

- From the video, a rough implementation of the structure would look like this:

```rust

// uses this to keep track of how its borrowed

enum RefState {

Unshared, // noone has a reference

Shared(usize), // there are n shared references

Exclusive, // someone has an exclusive reference

}

struct RefCell<T> {

value: UnsafeCell<T>,

state: RefState,

}

```

- The basic api should be something like:

- `borrow_mut() -> Option<&mut T>` returns `None` if it has already been borrowed (exclusive/shared)

- `borrow() -> Option<&T>` returns `None` if there has already been an exclusive borrow

( _there signatures are for understanding. the actual types will differ_ )

- But now, we see that its not possble to implement this api directly with

a simple `RefState` because we would have to mutate the state with a shared

reference.

- Here, wrapping the state in a `Cell` would solve the problem. Because `Cell`

allows us to _mutate using a shared reference_. Thus the structure

becomes:

```rust

struct RefCell<T> {

value: UnsafeCell<T>,

state: Cell<RefState>,

}

```

- This means that `RefState` would have to implement the `Copy` trait too

- Also, similar to `Cell`, `RefCell` is not thread safe

- In practice, if we are implementing `RefCell` ourselves, we would return custom

types, say `Ref` and `RefMut` for the `borrow` and `borrow_mut` methods. Now,

we can have our own impls for the `Drop`, `Deref` and `DerefMut` traits on

these new types to keep our state updated.

This allows us to gurantee safety for our implementation

Do check the video referenced above for the implementations and more explanation.