mail_headers/
error.rs

1//! module contains the (new) errors emitted by this crate
2use std::fmt::{self, Display};
3
4use failure::{Fail, Context, Error as FError, Backtrace};
5
6use ::name::HeaderName;
7
8/// This error can occur if different implementations for the
9/// same header (e.g. `Subject`) where used in the same `HeaderMap`.
10#[derive(Debug, Fail)]
11#[fail(display = "cast error caused by mixing different header implementations for {}", header_name)]
12pub struct HeaderTypeError {
13    header_name: HeaderName,
14    backtrace: Backtrace
15}
16
17impl HeaderTypeError {
18    pub fn new(name: HeaderName) -> Self {
19        HeaderTypeError {
20            header_name: name,
21            backtrace: Backtrace::new()
22        }
23    }
24
25    pub fn new_with_backtrace(name: HeaderName, backtrace: Backtrace) -> Self {
26        HeaderTypeError {
27            header_name: name,
28            backtrace
29        }
30    }
31}
32
33/// A validator specified in a header definition failed.
34///
35/// Common validators are e.g. to make sure that if a
36/// From header has multiple mailboxes that there is
37/// a Sender header etc.
38#[derive(Debug, Fail)]
39pub enum HeaderValidationError {
40    #[fail(display = "{}", _0)]
41    BuildIn(Context<BuildInValidationError>),
42    #[fail(display = "{}", _0)]
43    Custom(FError)
44}
45
46impl From<BuildInValidationError> for HeaderValidationError {
47    fn from(err: BuildInValidationError) -> Self {
48        HeaderValidationError::BuildIn(Context::new(err))
49    }
50}
51
52impl From<Context<BuildInValidationError>> for HeaderValidationError {
53    fn from(err: Context<BuildInValidationError>) -> Self {
54        HeaderValidationError::BuildIn(err)
55    }
56}
57
58/// The build-in error variants (error kinds) which can be returned
59/// when running a header map validator.
60#[derive(Copy, Clone, Debug, Fail, PartialEq, Eq, Hash)]
61pub enum BuildInValidationError {
62
63    /// This error is returned by `use_contextual_validators` if there is a "max one" inconsistency.
64    ///
65    /// I.e. if multiple implementations of the same header are used in the same map but
66    /// the implementations do not agree on wether or not the header can appear at most one
67    /// time in a header section.
68    #[fail(display = "{} header field contained both \"multi\" and \"max one\" header impl", header_name)]
69    MaxOneInconsistency { header_name: &'static str },
70
71    #[fail(display = "{} header field can appear at most one time in a header map", header_name)]
72    MoreThenOne { header_name: &'static str },
73
74    #[fail(display = "From field contained multiple addresses but no Sender field was set")]
75    MultiMailboxFromWithoutSender,
76
77    #[fail(display = "each resent block must have a resent-date field")]
78    ResentDateFieldMissing,
79
80    #[fail(display = "Resent-From field in resent block without a Resent-Sender field")]
81    MultiMailboxResentFromWithoutResentSender
82}
83
84macro_rules! header_validation_bail {
85    (kind: $($tt:tt)*) => ({
86        let build_in = $crate::error::BuildInValidationError::$($tt)*;
87        return Err(HeaderValidationError::BuildIn(::failure::Context::new(build_in)));
88    });
89}
90
91
92/// Helper type which is either a `Backtrace` or an full `failure::Error`.
93///
94/// This can be used to either just contain a backtrace into an custom
95/// error or to chain it in front of another error without adding another
96/// backtrace, depending on the creating context.
97#[derive(Debug)]
98pub enum ChainTail {
99    Backtrace(Backtrace),
100    Error(FError)
101}
102
103impl ChainTail {
104
105    fn backtrace(&self) -> &Backtrace {
106        match *self {
107            ChainTail::Backtrace(ref trace) => trace,
108            ChainTail::Error(ref error) => error.backtrace()
109        }
110    }
111
112    fn as_fail(&self) -> Option<&Fail> {
113        match *self {
114            ChainTail::Backtrace(_) => None,
115            ChainTail::Error(ref error) => Some(error.as_fail())
116        }
117    }
118}
119
120/// Creating a (header field) component from the given data failed
121///
122/// A good example converting a string to a mailbox by parsing it,
123/// or more concretely failing to do so because it's not a valid
124/// mail address.
125#[derive(Debug)]
126pub struct ComponentCreationError {
127    component: &'static str,
128    backtrace: ChainTail,
129    str_context: Option<String>
130}
131
132impl ComponentCreationError {
133
134    /// create a new `ComponentCreationError` based on a different error and the name of the component
135    ///
136    /// The name is normally the type name, for example `Email`, `Mailbox` etc.
137    pub fn from_parent<P>(parent: P, component: &'static str) -> Self
138        where P: Into<FError>
139    {
140        ComponentCreationError {
141            component,
142            backtrace: ChainTail::Error(parent.into()),
143            str_context: None
144        }
145    }
146
147    /// creates a new `ComponentCreationError` based on the components name
148    ///
149    /// The name is normally the type name, for example `Email`, `Mailbox` etc.
150    pub fn new(component: &'static str) -> Self {
151        ComponentCreationError {
152            component,
153            backtrace: ChainTail::Backtrace(Backtrace::new()),
154            str_context: None
155        }
156    }
157
158    /// creates a new `ComponentCreationError` based on the components name with a str_context
159    ///
160    /// The name is normally the type name, for example `Email`, `Mailbox` etc.
161    ///
162    /// The `str_context` is a snipped of text which can help a human to identify the
163    /// invalid parts, e.g. for parsing a email it could be the invalid email address.
164    pub fn new_with_str<I>(component: &'static str, str_context: I) -> Self
165        where I: Into<String>
166    {
167        ComponentCreationError {
168            component,
169            backtrace: ChainTail::Backtrace(Backtrace::new()),
170            str_context: Some(str_context.into())
171        }
172    }
173
174    pub fn str_context(&self) -> Option<&str> {
175        self.str_context.as_ref().map(|s|&**s)
176    }
177
178    pub fn set_str_context<I>(&mut self, ctx: I)
179        where I: Into<String>
180    {
181        self.str_context = Some(ctx.into());
182    }
183
184    pub fn with_str_context<I>(mut self, ctx: I) -> Self
185        where I: Into<String>
186    {
187        self.set_str_context(ctx);
188        self
189    }
190}
191
192impl Fail for ComponentCreationError {
193    fn cause(&self) -> Option<&Fail> {
194        self.backtrace.as_fail()
195    }
196    fn backtrace(&self) -> Option<&Backtrace> {
197        Some(self.backtrace.backtrace())
198    }
199}
200
201impl Display for ComponentCreationError {
202    fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
203        write!(fter, "creating component {} failed", self.component)
204    }
205}