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