Skip to main content

x_pipe_rs/
error.rs

1//! Pipeline error types.
2//!
3//! Each pipeline stage variant has its own error struct, collected
4//! under the top-level [`PipelineError`] enum.  All error types
5//! implement [`Display`] and [`std::error::Error`] by hand.
6
7use std::fmt;
8
9/// Name identifying a candidate source.
10#[derive(Debug, Clone)]
11pub struct SourceName(String);
12
13impl SourceName {
14    /// Create a new source name.
15    #[must_use]
16    pub fn new(name: impl Into<String>) -> Self {
17        Self(name.into())
18    }
19
20    /// The name as a string slice.
21    #[must_use]
22    pub fn as_str(&self) -> &str {
23        &self.0
24    }
25}
26
27impl fmt::Display for SourceName {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        write!(f, "{}", self.0)
30    }
31}
32
33/// Error from a candidate source.
34#[derive(Debug)]
35pub struct SourceError {
36    source_name: SourceName,
37    detail: String,
38}
39
40impl SourceError {
41    /// Create a new source error.
42    #[must_use]
43    pub fn new(source_name: SourceName, detail: impl Into<String>) -> Self {
44        Self {
45            source_name,
46            detail: detail.into(),
47        }
48    }
49
50    /// Which source failed.
51    #[must_use]
52    pub fn source_name(&self) -> &SourceName {
53        &self.source_name
54    }
55
56    /// Detail message.
57    #[must_use]
58    pub fn detail(&self) -> &str {
59        &self.detail
60    }
61}
62
63impl fmt::Display for SourceError {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "source '{}': {}", self.source_name, self.detail)
66    }
67}
68
69impl std::error::Error for SourceError {}
70
71/// Error from a hydration stage.
72#[derive(Debug)]
73pub struct HydrationError {
74    detail: String,
75}
76
77impl HydrationError {
78    /// Create a new hydration error.
79    #[must_use]
80    pub fn new(detail: impl Into<String>) -> Self {
81        Self {
82            detail: detail.into(),
83        }
84    }
85
86    /// Detail message.
87    #[must_use]
88    pub fn detail(&self) -> &str {
89        &self.detail
90    }
91}
92
93impl fmt::Display for HydrationError {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        write!(f, "hydration: {}", self.detail)
96    }
97}
98
99impl std::error::Error for HydrationError {}
100
101/// Error from a filter stage.
102#[derive(Debug)]
103pub struct FilterError {
104    detail: String,
105}
106
107impl FilterError {
108    /// Create a new filter error.
109    #[must_use]
110    pub fn new(detail: impl Into<String>) -> Self {
111        Self {
112            detail: detail.into(),
113        }
114    }
115
116    /// Detail message.
117    #[must_use]
118    pub fn detail(&self) -> &str {
119        &self.detail
120    }
121}
122
123impl fmt::Display for FilterError {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        write!(f, "filter: {}", self.detail)
126    }
127}
128
129impl std::error::Error for FilterError {}
130
131/// Error from a scoring stage.
132#[derive(Debug)]
133pub struct ScoringError {
134    detail: String,
135}
136
137impl ScoringError {
138    /// Create a new scoring error.
139    #[must_use]
140    pub fn new(detail: impl Into<String>) -> Self {
141        Self {
142            detail: detail.into(),
143        }
144    }
145
146    /// Detail message.
147    #[must_use]
148    pub fn detail(&self) -> &str {
149        &self.detail
150    }
151}
152
153impl fmt::Display for ScoringError {
154    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155        write!(f, "scoring: {}", self.detail)
156    }
157}
158
159impl std::error::Error for ScoringError {}
160
161/// Error from a selection stage.
162#[derive(Debug)]
163pub struct SelectionError {
164    detail: String,
165}
166
167impl SelectionError {
168    /// Create a new selection error.
169    #[must_use]
170    pub fn new(detail: impl Into<String>) -> Self {
171        Self {
172            detail: detail.into(),
173        }
174    }
175
176    /// Detail message.
177    #[must_use]
178    pub fn detail(&self) -> &str {
179        &self.detail
180    }
181}
182
183impl fmt::Display for SelectionError {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        write!(f, "selection: {}", self.detail)
186    }
187}
188
189impl std::error::Error for SelectionError {}
190
191/// Error from a side-effect stage.
192#[derive(Debug)]
193pub struct SideEffectError {
194    detail: String,
195}
196
197impl SideEffectError {
198    /// Create a new side-effect error.
199    #[must_use]
200    pub fn new(detail: impl Into<String>) -> Self {
201        Self {
202            detail: detail.into(),
203        }
204    }
205
206    /// Detail message.
207    #[must_use]
208    pub fn detail(&self) -> &str {
209        &self.detail
210    }
211}
212
213impl fmt::Display for SideEffectError {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        write!(f, "side effect: {}", self.detail)
216    }
217}
218
219impl std::error::Error for SideEffectError {}
220
221/// Top-level pipeline error.
222///
223/// Each variant wraps the error type from a specific stage.
224#[derive(Debug)]
225pub enum PipelineError {
226    /// A candidate source failed.
227    Source(SourceError),
228    /// Hydration failed.
229    Hydration(HydrationError),
230    /// A filter failed.
231    Filter(FilterError),
232    /// Scoring failed.
233    Scoring(ScoringError),
234    /// Selection failed.
235    Selection(SelectionError),
236    /// A side effect failed.
237    SideEffect(SideEffectError),
238}
239
240impl fmt::Display for PipelineError {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        match self {
243            Self::Source(e) => write!(f, "pipeline error: {e}"),
244            Self::Hydration(e) => write!(f, "pipeline error: {e}"),
245            Self::Filter(e) => write!(f, "pipeline error: {e}"),
246            Self::Scoring(e) => write!(f, "pipeline error: {e}"),
247            Self::Selection(e) => write!(f, "pipeline error: {e}"),
248            Self::SideEffect(e) => write!(f, "pipeline error: {e}"),
249        }
250    }
251}
252
253impl std::error::Error for PipelineError {
254    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
255        match self {
256            Self::Source(e) => Some(e),
257            Self::Hydration(e) => Some(e),
258            Self::Filter(e) => Some(e),
259            Self::Scoring(e) => Some(e),
260            Self::Selection(e) => Some(e),
261            Self::SideEffect(e) => Some(e),
262        }
263    }
264}
265
266impl From<SourceError> for PipelineError {
267    fn from(e: SourceError) -> Self {
268        Self::Source(e)
269    }
270}
271
272impl From<HydrationError> for PipelineError {
273    fn from(e: HydrationError) -> Self {
274        Self::Hydration(e)
275    }
276}
277
278impl From<FilterError> for PipelineError {
279    fn from(e: FilterError) -> Self {
280        Self::Filter(e)
281    }
282}
283
284impl From<ScoringError> for PipelineError {
285    fn from(e: ScoringError) -> Self {
286        Self::Scoring(e)
287    }
288}
289
290impl From<SelectionError> for PipelineError {
291    fn from(e: SelectionError) -> Self {
292        Self::Selection(e)
293    }
294}
295
296impl From<SideEffectError> for PipelineError {
297    fn from(e: SideEffectError) -> Self {
298        Self::SideEffect(e)
299    }
300}