spire_core/worker/
outcome.rs1use std::convert::Infallible;
2use std::time::Duration;
3
4use crate::crawler::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 Fatal(Error),
39}
40
41impl Outcome {
42 pub const fn retry() -> Self {
44 Self::Retry { after: None }
45 }
46
47 pub const fn retry_after(delay: Duration) -> Self {
49 Self::Retry { after: Some(delay) }
50 }
51
52 pub const fn backoff(duration: Duration) -> Self {
54 Self::Backoff {
55 scope: Scope::SameTag,
56 duration,
57 }
58 }
59
60 pub const fn abort() -> Self {
62 Self::Abort(Scope::SameTag)
63 }
64
65 pub fn abort_tag(tag: impl Into<Tag>) -> Self {
67 Self::Abort(Scope::Tag(tag.into()))
68 }
69
70 pub fn backoff_tag(tag: impl Into<Tag>, duration: Duration) -> Self {
72 Self::Backoff {
73 scope: Scope::Tag(tag.into()),
74 duration,
75 }
76 }
77}
78
79#[derive(Debug, Clone, Default, PartialEq, Eq)]
81pub enum Scope {
82 #[default]
85 SameTag,
86 Tag(Tag),
88}
89
90pub trait IntoOutcome {
92 fn into_outcome(self) -> Outcome;
94}
95
96impl IntoOutcome for Outcome {
97 fn into_outcome(self) -> Outcome {
98 self
99 }
100}
101
102impl IntoOutcome for () {
103 fn into_outcome(self) -> Outcome {
104 Outcome::Continue
105 }
106}
107
108impl IntoOutcome for Infallible {
109 fn into_outcome(self) -> Outcome {
110 match self {}
111 }
112}
113
114impl IntoOutcome for Error {
115 fn into_outcome(self) -> Outcome {
116 Outcome::Fail(self)
117 }
118}
119
120impl IntoOutcome for BoxError {
121 fn into_outcome(self) -> Outcome {
125 Outcome::Fail(Error::from_boxed(crate::ErrorKind::Worker, self))
126 }
127}
128
129impl<T> IntoOutcome for Option<T>
130where
131 T: IntoOutcome,
132{
133 fn into_outcome(self) -> Outcome {
134 self.map_or(Outcome::Continue, IntoOutcome::into_outcome)
135 }
136}
137
138impl<T, E> IntoOutcome for Result<T, E>
139where
140 T: IntoOutcome,
141 E: IntoOutcome,
142{
143 fn into_outcome(self) -> Outcome {
144 match self {
145 Ok(value) => value.into_outcome(),
146 Err(error) => error.into_outcome(),
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use crate::{ErrorKind, Result};
155
156 #[test]
157 fn conversions() {
158 assert!(matches!(().into_outcome(), Outcome::Continue));
159 assert!(matches!(None::<Outcome>.into_outcome(), Outcome::Continue));
160
161 let ok: Result<()> = Ok(());
162 assert!(matches!(ok.into_outcome(), Outcome::Continue));
163
164 let err: Result<()> = Err(Error::new(ErrorKind::Http));
165 assert!(matches!(err.into_outcome(), Outcome::Fail(_)));
166
167 let retry: Result<(), Outcome> = Err(Outcome::retry());
168 assert!(matches!(
169 retry.into_outcome(),
170 Outcome::Retry { after: None }
171 ));
172 }
173}