Rust's borrow checker is often described as a compile-time reader-writer lock. Stacked and Tree Borrows admit a similar analogy:
RwLock |
Safe Rust borrow checker | Stacked Borrows | Tree Borrows |
---|---|---|---|
read |
& borrow |
SharedReadOnly borrow |
New Frozen pointer |
drop(ReadGuard) |
& leaves scope |
Pop [¬P]SharedReadOnly upon lower write |
[¬P]Frozen → Disabled upon foreign write |
write |
&mut borrow |
New Unique pointer |
- [1] |
WriteGuard::downgrade |
![]() |
![]() |
[¬P]Active → [¬P]Frozen upon foreign read |
drop(WriteGuard) |
&mut leaves scope |
[¬P]Unique → Disabled upon lower read, or pop upon lower write |
[¬P]Active → Disabled upon foreign write |
upgradable_read |
Two-phase borrow reservation | New SharedReadWrite pointer [2] |
New Reserved pointer |
upgrade |
Two-phase borrow activation | - [2:1] | Unconflicted Reserved → Active upon child write |
downgrade_to_upgradable |
![]() |
![]() |
![]() |
UpgradableReadGuard::downgrade |
- | - [2:2] | - [3] |
drop(UpgradableReadGuard) |
Reserved two-phase borrow leaves scope | - [2:3] | Non-interior-mutable [¬P]Active → Disabled upon foreign write |
First, I'll admit that my understanding of Stacked Borrows is shaky compared to
the other models, and it's also the model where the RwLock
analogy works least
well. So I may have made mistakes in that column. That said, my main takeaways:
- The equivalent of
WriteGuard::downgrade
would be a very nice operation to have in safe Rust. See this recent topic for more discussion.- Of course, this requires the underlying aliasing model to support it. Tree Borrows does and Stacked Borrows doesn't, so this is a point in favor of Tree Borrows.
- In Stacked Borrows,
&mut
immediately asserts uniqueness (corresponds towrite()
); in Tree Borrows, this assertion is delayed (corresponds toupgradable_read()
). Whichever of the two options is eventually chosen as the "default" behavior of&mut
, it might be desirable to make the other behavior also available with a secondary syntax. - No model supports the equivalent of
WriteGuard::downgrade_to_upgradable
. Is this something that can or should be provided? Does it make any sense? - Two-phased borrows (equivalent of
upgradable_read
) are only supported by the safe Rust borrow checker in the limited case of method call receivers. Is it possible or desirable to expose them to safe code more generally?
You can just make a
Reserved
and write immediately after ↩︎The
RwLock
analogy breaks down here. Stacked BorrowsSharedReadWrite
never transitions toUnique
even upon non-interior-mutable writes. ↩︎ ↩︎ ↩︎ ↩︎In the original Tree Borrows, this cell would correspond to the
[P]Reserved
→[P]Frozen
transition upon a foreign read. However, that part of the model was changed; foreign reads now set theconflicted
flag of[P]Reserved
, but this only matters until function exit. ↩︎