tycho_util/transactional/
mod.rs1use 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
15pub 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 }
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}