fast_stm/
result.rs

1// regular transaction
2
3/// Error of a single step of a transaction.
4#[derive(Eq, PartialEq, Clone, Copy, Debug, thiserror::Error)]
5pub enum StmError {
6    /// The call failed, because a variable, the computation
7    /// depends on, has changed.
8    #[error("Transaction failure signal")]
9    Failure,
10
11    /// `retry` was called.
12    ///
13    /// It may block until at least one read variable has changed.
14    #[error("Transaction retry signal")]
15    Retry,
16}
17
18/// Return type of a transaction body.
19///
20/// It is the result of a single step of a STM calculation. It informs of success or the type
21/// of failure. Normally you should not use it directly. Especially recovering from an error,
22/// e.g. by using `action1.or(action2)` can break the semantics of stm, and cause delayed
23/// wakeups or deadlocks.
24///
25/// For the later case, there is the `transaction.or(action1, action2)`, that
26/// is safe to use.
27pub type StmClosureResult<T> = Result<T, StmError>;
28
29// fallible transaction
30
31/// Error of a single step of a fallible transaction.
32#[derive(Eq, PartialEq, Clone, Copy, Debug, thiserror::Error)]
33pub enum TransactionError<E> {
34    /// Failed due to a regular [`StmError`].
35    Stm(#[from] StmError),
36    /// Failed due to manual cancelling (e.g. a call to `abort` in the transaction's body).
37    Abort(E),
38}
39
40/// Return type of a fallible transaction body.
41pub type TransactionClosureResult<T, E> = Result<T, TransactionError<E>>;
42
43/// Result of a fallible transaction.
44///
45/// A given transaction can finish in three different ways:
46/// - it is validated, and possibly returns an output value,
47/// - it is manually cancelled, and possibly returns a user-defined error,
48/// - it is cancelled through regular STM control flow.
49///
50/// Each variant of this enum represents a case. All of the associated methods behave
51/// like their equivalent for [`std::result::Result`].
52#[derive(Eq, PartialEq, Clone, Copy, Debug)]
53#[must_use = "this `TransactionResult` may model an error, which should be handled"]
54pub enum TransactionResult<T, E> {
55    /// Transaction completed successfully.
56    Validated(T),
57    /// Transaction was manually aborted.
58    Cancelled(E),
59    /// Transaction was aorted through standard control flow.
60    Abandoned,
61}
62
63impl<T, E> TransactionResult<T, E> {
64    /// Returns `true` if the result is [`Validated`][Self::Validated].
65    pub fn is_validated(&self) -> bool {
66        matches!(self, Self::Validated(_))
67    }
68
69    /// Returns `true` if the result is [`Validated`][Self::Validated]
70    /// and the value inside of it matches a predicate.
71    pub fn is_validated_and(self, f: impl FnOnce(T) -> bool) -> bool {
72        match self {
73            Self::Validated(t) => f(t),
74            Self::Cancelled(_) | Self::Abandoned => false,
75        }
76    }
77
78    /// Returns `true` if the result is [`Cancelled`][Self::Cancelled].
79    pub fn is_cancelled(&self) -> bool {
80        matches!(self, Self::Cancelled(_))
81    }
82
83    /// Returns `true` if the result is [`Cancelled`][Self::Cancelled]
84    /// and the value inside of it matches a predicate.
85    pub fn is_cancelled_and(self, f: impl FnOnce(E) -> bool) -> bool {
86        match self {
87            Self::Cancelled(e) => f(e),
88            Self::Validated(_) | Self::Abandoned => false,
89        }
90    }
91
92    /// Converts `self: TransactionResult<T, E>` to [`Option<T>`], consuming `self`,
93    /// and discarding the error, if any.
94    pub fn validated(self) -> Option<T> {
95        match self {
96            Self::Validated(t) => Some(t),
97            Self::Cancelled(_) | Self::Abandoned => None,
98        }
99    }
100
101    /// Converts `self: TransactionResult<T, E>` to [`Option<E>`], consuming `self`,
102    /// and discarding the success value, if any.    
103    pub fn cancelled(self) -> Option<E> {
104        match self {
105            Self::Cancelled(e) => Some(e),
106            Self::Validated(_) | Self::Abandoned => None,
107        }
108    }
109
110    /// Returns `true` if the result is [`Abandoned`][Self::Abandoned].
111    pub fn failed(self) -> bool {
112        matches!(self, Self::Abandoned)
113    }
114
115    /// Returns the contained [`Validated`][Self::Validated] value, consuming `self`.
116    ///
117    /// # Panics
118    ///
119    /// Panics if the value is a [`Cancelled`][Self::Cancelled] or [`Abandoned`][Self::Abandoned],
120    /// with a panic message including the passed message, and the content of
121    /// [`Cancelled`][Self::Cancelled] if applicable.
122    pub fn expect(self, msg: &str) -> T
123    where
124        E: std::fmt::Debug,
125    {
126        match self {
127            Self::Validated(t) => t,
128            Self::Cancelled(e) => panic!("{msg}: {e:?}"),
129            Self::Abandoned => panic!("{msg}"),
130        }
131    }
132
133    /// Returns the contained [`Cancelled`][Self::Cancelled] error, consuming `self`.
134    ///
135    /// # Panics
136    ///
137    /// Panics if the value is a [`Validated`][Self::Validated] or [`Abandoned`][Self::Abandoned],
138    /// with a panic message including the passed message, and the content of
139    /// [`Validated`][Self::Validated] if applicable.
140    pub fn expect_err(self, msg: &str) -> E
141    where
142        T: std::fmt::Debug,
143    {
144        match self {
145            Self::Validated(t) => panic!("{msg}: {t:?}"),
146            Self::Cancelled(e) => e,
147            Self::Abandoned => panic!("{msg}"),
148        }
149    }
150
151    /// Returns the contained [`Validated`][Self::Validated] value, consuming `self`.
152    ///
153    /// # Panics
154    ///
155    /// Panics if the value is a [`Cancelled`][Self::Cancelled] or [`Abandoned`][Self::Abandoned], with
156    /// a panic message specified by the content of [`Cancelled`][Self::Cancelled] if applicable.    
157    pub fn unwrap(self) -> T
158    where
159        E: std::fmt::Debug,
160    {
161        match self {
162            Self::Validated(t) => t,
163            Self::Cancelled(e) => {
164                panic!("called `TransactionResult::unwrap()` on a `Cancelled` value: {e:?}")
165            }
166            Self::Abandoned => {
167                panic!("called `TransactionResult::unwrap()` on a `Abandoned` value")
168            }
169        }
170    }
171
172    /// Returns the contained [`Cancelled`][Self::Cancelled] error, consuming `self`.
173    ///
174    /// # Panics
175    ///
176    /// Panics if the value is a [`Validated`][Self::Validated] or [`Abandoned`][Self::Abandoned], with
177    /// a panic message specified by the content of [`Validated`][Self::Validated] if applicable.    
178    pub fn unwrap_err(self) -> E
179    where
180        T: std::fmt::Debug,
181    {
182        match self {
183            Self::Validated(t) => {
184                panic!("called `TransactionResult::unwrap_err()` on a `Validated` value: {t:?}")
185            }
186            Self::Cancelled(e) => e,
187            Self::Abandoned => {
188                panic!("called `TransactionResult::unwrap_err()` on a `Abandoned` value")
189            }
190        }
191    }
192
193    /// Returns the contained [`Validated`][Self::Validated] value or a default value,
194    /// consuming `self`.
195    ///
196    /// If the value is a [`Cancelled`][Self::Cancelled] or [`Abandoned`][Self::Abandoned], the `Default`
197    /// implementation of `T` is called to return a value.    
198    pub fn unwrap_or_default(self) -> T
199    where
200        T: Default,
201    {
202        match self {
203            Self::Validated(t) => t,
204            Self::Cancelled(_) | Self::Abandoned => Default::default(),
205        }
206    }
207}