rust 39 lines · 8 steps

A RAII rollback guard in Rust

A ScopeGuard runs a compensating action on drop unless you commit, giving you automatic rollback on early return.

Explained by highlit
1pub struct ScopeGuard<F: FnMut()> {
2 rollback: F,
3 active: bool,
4}
5 
6impl<F: FnMut()> ScopeGuard<F> {
7 pub fn new(rollback: F) -> Self {
8 Self { rollback, active: true }
9 }
10 
11 pub fn commit(mut self) {
12 self.active = false;
13 }
14}
15 
16impl<F: FnMut()> Drop for ScopeGuard<F> {
17 fn drop(&mut self) {
18 if self.active {
19 (self.rollback)();
20 }
21 }
22}
23 
24pub fn apply_credit(account: &Rc<RefCell<Account>>, amount: u64) -> Result<(), TransferError> {
25 account.borrow_mut().balance += amount;
26 
27 let guard = {
28 let account = Rc::clone(account);
29 ScopeGuard::new(move || {
30 account.borrow_mut().balance -= amount;
31 })
32 };
33 
34 ledger::record(account.borrow().id, amount)?;
35 notify::credit_applied(account.borrow().id, amount)?;
36 
37 guard.commit();
38 Ok(())
39}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1RAII lets you tie cleanup to scope exit so every early return runs it automatically.
  2. 2Consuming self in a method disarms a guard by moving it out of drop's reach at commit time.
  3. 3Capturing a cloned Rc by move lets the rollback closure outlive the surrounding block.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A RAII rollback guard in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code