RefCell

Reference Video | Rust Docs

  • 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:

    
    #![allow(unused_variables)]
    fn main() {
      // 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:

    
    #![allow(unused_variables)]
    fn main() {
        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.