spire_core/worker/
outcome.rs1use std::convert::Infallible;
2use std::time::Duration;
3
4use crate::request::Tag;
5use crate::{BoxError, Error};
6
7#[must_use]
9#[derive(Debug, Default)]
10pub enum Outcome {
11 #[default]
13 Continue,
14 Retry {
17 after: Option<Duration>,
19 },
20 Backoff {
23 scope: Scope,
25 duration: Duration,
27 },
28 Abort(Scope),
31 Stop,
33 Fail(Error),
36}
37
38impl Outcome {
39 pub const fn retry() -> Self {
41 Self::Retry { after: None }
42 }
43
44 pub const fn retry_after(delay: Duration) -> Self {
46 Self::Retry { after: Some(delay) }
47 }
48
49 pub const fn backoff(duration: Duration) -> Self {
51 Self::Backoff {
52 scope: Scope::Owner,
53 duration,
54 }
55 }
56
57 pub const fn abort() -> Self {
59 Self::Abort(Scope::Owner)
60 }
61
62 pub fn abort_tag(tag: impl Into<Tag>) -> Self {
64 Self::Abort(Scope::Tag(tag.into()))
65 }
66
67 pub fn backoff_tag(tag: impl Into<Tag>, duration: Duration) -> Self {
69 Self::Backoff {
70 scope: Scope::Tag(tag.into()),
71 duration,
72 }
73 }
74}
75
76#[derive(Debug, Clone, Default, PartialEq, Eq)]
78pub enum Scope {
79 #[default]
82 Owner,
83 Tag(Tag),
85}
86
87pub trait IntoOutcome {
89 fn into_outcome(self) -> Outcome;
91}
92
93impl IntoOutcome for Outcome {
94 fn into_outcome(self) -> Outcome {
95 self
96 }
97}
98
99impl IntoOutcome for () {
100 fn into_outcome(self) -> Outcome {
101 Outcome::Continue
102 }
103}
104
105impl IntoOutcome for Infallible {
106 fn into_outcome(self) -> Outcome {
107 match self {}
108 }
109}
110
111impl IntoOutcome for Error {
112 fn into_outcome(self) -> Outcome {
113 Outcome::Fail(self)
114 }
115}
116
117impl IntoOutcome for BoxError {
118 fn into_outcome(self) -> Outcome {
122 Outcome::Fail(Error::from_boxed(crate::ErrorKind::Worker, self))
123 }
124}
125
126impl<T> IntoOutcome for Option<T>
127where
128 T: IntoOutcome,
129{
130 fn into_outcome(self) -> Outcome {
131 self.map_or(Outcome::Continue, IntoOutcome::into_outcome)
132 }
133}
134
135impl<T, E> IntoOutcome for Result<T, E>
136where
137 T: IntoOutcome,
138 E: IntoOutcome,
139{
140 fn into_outcome(self) -> Outcome {
141 match self {
142 Ok(value) => value.into_outcome(),
143 Err(error) => error.into_outcome(),
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use crate::ErrorKind;
152
153 #[test]
154 fn conversions() {
155 assert!(matches!(().into_outcome(), Outcome::Continue));
156 assert!(matches!(None::<Outcome>.into_outcome(), Outcome::Continue));
157
158 let ok: Result<(), Error> = Ok(());
159 assert!(matches!(ok.into_outcome(), Outcome::Continue));
160
161 let err: Result<(), Error> = Err(Error::new(ErrorKind::Http));
162 assert!(matches!(err.into_outcome(), Outcome::Fail(_)));
163
164 let retry: Result<(), Outcome> = Err(Outcome::retry());
165 assert!(matches!(
166 retry.into_outcome(),
167 Outcome::Retry { after: None }
168 ));
169 }
170}