Struct Undo
pub struct Undo<T, F>where
F: FnOnce(T),{ /* private fields */ }Expand description
An RAII guard to rollback and undo something on (early) drop.
Dereferences to its inner T and its undo function is given the T on
drop.
When all of the changes that need to happen together have happened, you can
call Undo::commit to disable the guard and commit the associated side
effects.
§Example
use std::cell::Cell;
use wasmtime_internal_core::{error::Result, undo::Undo};
/// Some big ball of state that must always be coherent.
pub struct Context {
// ...
}
impl Context {
/// Perform some incremental mutation to `self`, which might not leave
/// it in a valid state unless its whole batch of work is completed.
fn do_thing(&mut self, arg: u32) -> Result<()> {
// ...
}
/// Undo the side effects of `self.do_thing(arg)` for when we need to
/// roll back mutations.
fn undo_thing(&mut self, arg: u32) {
// ...
}
/// Call `self.do_thing(arg)` for each `arg` in `args`.
///
/// However, if any `self.do_thing(arg)` call fails, make sure that
/// we roll back to the original state by calling `self.undo_thing(arg)`
/// for all the `self.do_thing(arg)` calls that already succeeded. This
/// way we never leave `self` in a state where things got half-done.
pub fn do_all_or_nothing(&mut self, args: &[u32]) -> Result<()> {
// Counter for our progress, so that we know how much to work undo upon
// failure.
let num_things_done = Cell::new(0);
// Wrap the `Context` in an `Undo` that rolls back our side effects if
// we early-exit this function via `?`-propagation or panic unwinding.
let mut ctx = Undo::new(self, |ctx| {
for arg in args.iter().take(num_things_done.get()) {
ctx.undo_thing(*arg);
}
});
// Do each piece of work!
for arg in args {
// Note: if this call returns an error that is `?`-propagated or
// triggers unwinding by panicking, then the work performed thus
// far will be rolled back when `ctx` is dropped.
ctx.do_thing(*arg)?;
// Update how much work has been completed.
num_things_done.set(num_things_done.get() + 1);
}
// We completed all of the work, so commit the `Undo` guard and
// disable its cleanup function.
Undo::commit(ctx);
Ok(())
}
}Implementations§
Trait Implementations§
Auto Trait Implementations§
impl<T, F> Freeze for Undo<T, F>
impl<T, F> RefUnwindSafe for Undo<T, F>where
T: RefUnwindSafe,
F: RefUnwindSafe,
impl<T, F> Send for Undo<T, F>
impl<T, F> Sync for Undo<T, F>
impl<T, F> Unpin for Undo<T, F>
impl<T, F> UnwindSafe for Undo<T, F>where
T: UnwindSafe,
F: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more