use crate::bindings::golem::api::host::{OplogIndex, get_oplog_index, set_oplog_index};
pub struct Checkpoint {
oplog_index: OplogIndex,
}
impl Default for Checkpoint {
fn default() -> Self {
Self::new()
}
}
impl Checkpoint {
pub fn new() -> Self {
Self {
oplog_index: get_oplog_index(),
}
}
pub fn revert(&self) -> ! {
set_oplog_index(self.oplog_index);
unreachable!()
}
pub fn run_or_revert<T, E>(&self, f: impl FnOnce() -> Result<T, E>) -> T {
match f() {
Ok(value) => value,
Err(_) => self.revert(),
}
}
pub async fn run_or_revert_async<T, E, F: std::future::Future<Output = Result<T, E>>>(
&self,
f: impl FnOnce() -> F,
) -> T {
match f().await {
Ok(value) => value,
Err(_) => self.revert(),
}
}
pub fn assert_or_revert(&self, condition: bool) {
if !condition {
self.revert();
}
}
}
pub trait CheckpointResultExt<T, E> {
fn unwrap_or_revert(self, checkpoint: &Checkpoint) -> T;
fn expect_or_revert(self, checkpoint: &Checkpoint, msg: &str) -> T;
}
impl<T, E> CheckpointResultExt<T, E> for Result<T, E> {
fn unwrap_or_revert(self, checkpoint: &Checkpoint) -> T {
match self {
Ok(value) => value,
Err(_) => checkpoint.revert(),
}
}
fn expect_or_revert(self, checkpoint: &Checkpoint, msg: &str) -> T {
match self {
Ok(value) => value,
Err(_) => {
eprintln!("{msg}");
checkpoint.revert();
}
}
}
}
pub trait CheckpointOptionExt<T> {
fn unwrap_or_revert(self, checkpoint: &Checkpoint) -> T;
fn expect_or_revert(self, checkpoint: &Checkpoint, msg: &str) -> T;
}
impl<T> CheckpointOptionExt<T> for Option<T> {
fn unwrap_or_revert(self, checkpoint: &Checkpoint) -> T {
match self {
Some(value) => value,
None => checkpoint.revert(),
}
}
fn expect_or_revert(self, checkpoint: &Checkpoint, msg: &str) -> T {
match self {
Some(value) => value,
None => {
eprintln!("{msg}");
checkpoint.revert();
}
}
}
}
pub fn with_checkpoint<T, E>(f: impl FnOnce(&Checkpoint) -> Result<T, E>) -> T {
let checkpoint = Checkpoint::new();
match f(&checkpoint) {
Ok(value) => value,
Err(_) => checkpoint.revert(),
}
}
pub async fn with_checkpoint_async<T, E, F: std::future::Future<Output = Result<T, E>>>(
f: impl FnOnce(&Checkpoint) -> F,
) -> T {
let checkpoint = Checkpoint::new();
match f(&checkpoint).await {
Ok(value) => value,
Err(_) => checkpoint.revert(),
}
}