orion_error/traits/contextual.rs
1use crate::core::OperationContext;
2
3/// Extension methods for attaching operation context and position to an error.
4///
5/// [`doing("...")`](ErrorWith::doing) and [`at("...")`](ErrorWith::at) are the
6/// primary ways to annotate where and what was happening when the error occurred.
7///
8/// Implemented for [`StructError`](crate::StructError) and
9/// `Result<T, E>` where `E: ErrorWith`.
10///
11/// # Example
12///
13/// ```rust
14/// use orion_error::prelude::*;
15/// use orion_error::UnifiedReason;
16///
17/// let err = StructError::from(UnifiedReason::validation_error())
18/// .doing("parse config") // what operation
19/// .at("config.toml"); // what resource
20///
21/// assert_eq!(err.action_main().as_deref(), Some("parse config"));
22/// assert_eq!(err.locator_main().as_deref(), Some("config.toml"));
23///
24/// // doing/at also works on Result chains:
25/// let result: Result<(), StructError<UnifiedReason>> =
26/// Err(StructError::from(UnifiedReason::validation_error()))
27/// .doing("validate")
28/// .at("input.json");
29/// assert!(result.is_err());
30/// ```
31pub trait ErrorWith {
32 fn position<S: Into<String>>(self, desc: S) -> Self;
33 fn with_context<C: Into<OperationContext>>(self, ctx: C) -> Self;
34 fn doing<S: Into<String>>(self, desc: S) -> Self
35 where
36 Self: Sized,
37 {
38 self.with_context(OperationContext::doing(desc))
39 }
40 fn at<C: Into<OperationContext>>(self, ctx: C) -> Self
41 where
42 Self: Sized,
43 {
44 self.with_context(ctx.into().into_at_context())
45 }
46}
47
48impl<T, E: ErrorWith> ErrorWith for Result<T, E> {
49 fn position<S: Into<String>>(self, desc: S) -> Self {
50 self.map_err(|e| e.position(desc))
51 }
52 fn with_context<C: Into<OperationContext>>(self, ctx: C) -> Self {
53 self.map_err(|e| e.with_context(ctx))
54 }
55}