Creative methods on interior mutability types

In the previous post Interior mutability patterns we looked at four different conventions that can be used to safely use interor mutability. We didn’t look further than the basic API, that was already plenty of material to cover.

Yet there are some creative methods that push the limit of those abstractions. Let’s explore them!

On container types:

method Cell Atomic¹ AtomicCell¹ RefCell Mutex RwLock OnceCell QCell TCell LCell
into_inner yes yes yes yes yes yes yes yes* yes* yes*
get_mut yes yes* yes yes yes yes yes* yes* yes*
as_ptr yes yes yes yes yes yes yes* yes yes yes
from_mut yes yes* (BoCell) yes* yes*
replace yes yes yes yes yes* yes* yes*
swap yes yes yes yes
update yes yes —* —* —*
as_slice_of_cells yes yes* yes*
with maybe maybe

On smart pointers:

method Ref RefMut MutexGuard RwLockReadGuard RwLockWriteGuard ReentrantMutexGuard
bump yes* yes* yes* yes
unlocked yes* yes* yes* yes
Condvar::wait yes yes* yes* yes*
map yes yes yes* yes* yes* yes
map_split yes yes yes* yes* yes* yes*
try_map yes* yes* yes* yes* yes* yes
downgrade yes*
upgrade yes* maybe

¹: In this post I use Atomic<T> to describe a wrapper based on atomic operations, and AtomicCell<T> to describe a lock-based solution for larger types.

*: possible, but not implemented (or not implemented in the standard library or main crate)

Read More

Interior mutability patterns

Rusts type system requires that there only ever is one mutable reference to a value or one or more shared references. What happens when you need multiple references to some value, but also need to mutate through them? We use a trick called interor mutability: to the outside world you act like a value is immutable so multiple references are allowed. But internally the type is actually mutable.

All types that provide interior mutability have an UnsafeCell at their core. UnsafeCell is the only primitive that allows multiple mutable pointers to its interior, without violating aliasing rules. The only way to use it safely is to only mutate the wrapped value when there are no other readers. No, the garantee has to be even stronger: we can not mutate it and can not create a mutable reference to the wrapped value while there are shared references to its value.

Both the book and the std::cell module give a good alternative explanation of interor mutability.

  • What are some patterns that have been developed to use interior mutability safely?
  • How do multithreaded synchronization primitives that provide interior mutability follow similar principles?
Read More

Writing a seqlock in Rust

A seqlock — or “sequence lock” — is an optimized implementation of a reader-writer lock. In a seqlock “the data can be ‘protected’ by a sequence number. The sequence number starts at zero, and is incremented before and after writing the object. Each reader checks the sequence number before and after reading. If both values are the same and even, then there cannot have been any concurrent increments, and the reader must have seen consistent data.”

Read More