Skip to main content

tycho_util/transactional/
mod.rs

1use std::ops::{Deref, DerefMut};
2
3pub mod btreemap;
4pub mod hashmap;
5pub mod option;
6pub mod value;
7
8pub trait Transactional {
9    fn begin(&mut self);
10    fn commit(&mut self);
11    fn rollback(&mut self);
12    fn in_tx(&self) -> bool;
13}
14
15/// RAII guard for `Transactional` types.
16/// Calls `begin()` on creation and `rollback()` on drop if not committed.
17pub struct TransactionGuard<'a, T: Transactional> {
18    inner: &'a mut T,
19    committed: bool,
20}
21
22impl<'a, T: Transactional> TransactionGuard<'a, T> {
23    pub fn new(inner: &'a mut T) -> Self {
24        inner.begin();
25        Self {
26            inner,
27            committed: false,
28        }
29    }
30
31    pub fn commit(mut self) {
32        self.inner.commit();
33        self.committed = true;
34    }
35}
36
37impl<T: Transactional> Drop for TransactionGuard<'_, T> {
38    fn drop(&mut self) {
39        if !self.committed {
40            self.inner.rollback();
41        }
42    }
43}
44
45impl<T: Transactional> Deref for TransactionGuard<'_, T> {
46    type Target = T;
47
48    fn deref(&self) -> &T {
49        self.inner
50    }
51}
52
53impl<T: Transactional> DerefMut for TransactionGuard<'_, T> {
54    fn deref_mut(&mut self) -> &mut T {
55        self.inner
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::transactional::value::TransactionalValue;
63
64    #[test]
65    fn guard_commits() {
66        let mut v = TransactionalValue::new(1);
67        {
68            let mut guard = TransactionGuard::new(&mut v);
69            **guard = 2;
70            guard.commit();
71        }
72        assert_eq!(*v, 2);
73    }
74
75    #[test]
76    fn guard_rollbacks_on_drop() {
77        let mut v = TransactionalValue::new(1);
78        {
79            let mut guard = TransactionGuard::new(&mut v);
80            **guard = 2;
81            // no commit - should rollback
82        }
83        assert_eq!(*v, 1);
84    }
85
86    #[test]
87    fn guard_deref() {
88        let mut v = TransactionalValue::new(42);
89        let guard = TransactionGuard::new(&mut v);
90        assert_eq!(**guard, 42);
91    }
92}