💾 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
⬅️ Previous capture (2020-11-07)
-=-=-=-=-=-=-
[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.