diff options
Diffstat (limited to 'core/src/error.rs')
-rw-r--r-- | core/src/error.rs | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/core/src/error.rs b/core/src/error.rs new file mode 100644 index 0000000..9f787c4 --- /dev/null +++ b/core/src/error.rs @@ -0,0 +1,293 @@ +//! Module containing all custom errors produced by this crate. +use std::fmt::{self, Display}; +use std::io; + +use failure::{Fail, Context, Backtrace}; + +use internals::error::EncodingError; +use headers::error::{ + BuildInValidationError, + HeaderTypeError, ComponentCreationError, + HeaderValidationError +}; +use ::IRI; +// errors from loading a Resource (which includes encoding it's body) +// / NotFound | IRI (no Backtrace neede) \ MailError::ResourceLoading +// ResourceError < LoadingFailed | chain Error / +// \ EncodingFailed | EncodingError (Backtrace!) > MailError::Encoding +// + +/// Error caused by failing to load an `Resource` +/// +#[derive(Debug, Fail)] +pub enum ResourceError { + /// The loading on itself failed. + #[fail(display = "{}", _0)] + Loading(ResourceLoadingError), + + /// The encoding of the resource failed. + /// + /// Note: Resources are encoded as this allows shared + /// resources to not be re-encoded every time they are + /// used. + #[fail(display = "{}", _0)] + Encoding(EncodingError) +} + +impl From<EncodingError> for ResourceError { + fn from(err: EncodingError) -> Self { + ResourceError::Encoding(err) + } +} + +impl From<ResourceLoadingError> for ResourceError { + fn from(err: ResourceLoadingError) -> Self { + ResourceError::Loading(err) + } +} + +/// Reasons why the loading of an `Resource` can fail. +#[derive(Copy, Clone, Debug, Fail, PartialEq, Eq, Hash)] +pub enum ResourceLoadingErrorKind { + /// The resource wasn't found. + #[fail(display = "resource not found")] + NotFound, + + /// The act of loading it failed (e.g. because of an I/0-Error) + #[fail(display = "loading failed")] + LoadingFailed, + + #[fail(display = "automatically detecting the media type failed")] + MediaTypeDetectionFailed +} + +/// The loading of an Resource failed. +#[derive(Debug)] +pub struct ResourceLoadingError { + inner: Context<ResourceLoadingErrorKind>, + iri: Option<IRI> +} + +impl Display for ResourceLoadingError { + fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.inner, fter) + } +} + +impl Fail for ResourceLoadingError { + fn cause(&self) -> Option<&Fail> { + self.inner.cause() + } + + fn backtrace(&self) -> Option<&Backtrace> { + self.inner.backtrace() + } +} + +impl ResourceLoadingError { + + /// The kind of error which caused the loading to fail. + pub fn kind(&self) -> ResourceLoadingErrorKind { + *self.inner.get_context() + } + + /// The source IRI which was used when failing to load the Resource. + pub fn source_iri(&self) -> Option<&IRI> { + self.iri.as_ref() + } + + /// Sets the source IRI if not already set and returns self. + pub fn with_source_iri_or_else<F>(mut self, func: F) -> Self + where F: FnOnce() -> Option<IRI> + { + if self.iri.is_none() { + self.iri = func(); + } + self + } +} + +impl From<ResourceLoadingErrorKind> for ResourceLoadingError { + fn from(err: ResourceLoadingErrorKind) -> Self { + ResourceLoadingError::from((None, err)) + } +} + +impl From<Context<ResourceLoadingErrorKind>> for ResourceLoadingError { + fn from(inner: Context<ResourceLoadingErrorKind>) -> Self { + ResourceLoadingError::from((None, inner)) + } +} + +impl From<(IRI, ResourceLoadingErrorKind)> for ResourceLoadingError { + fn from((iri, error_kind): (IRI, ResourceLoadingErrorKind)) -> Self { + ResourceLoadingError::from((Some(iri), error_kind)) + } +} + +impl From<(IRI, Context<ResourceLoadingErrorKind>)> for ResourceLoadingError { + fn from((iri, inner): (IRI, Context<ResourceLoadingErrorKind>)) -> Self { + ResourceLoadingError::from((Some(iri), inner)) + } +} + +impl From<(Option<IRI>, ResourceLoadingErrorKind)> for ResourceLoadingError { + fn from((iri, error_kind): (Option<IRI>, ResourceLoadingErrorKind)) -> Self { + ResourceLoadingError::from((iri, Context::new(error_kind))) + } +} + +impl From<(Option<IRI>, Context<ResourceLoadingErrorKind>)> for ResourceLoadingError { + fn from((iri, inner): (Option<IRI>, Context<ResourceLoadingErrorKind>)) -> Self { + ResourceLoadingError { + inner, iri + } + } +} + +impl From<io::Error> for ResourceLoadingError { + fn from(err: io::Error) -> Self { + err.context(ResourceLoadingErrorKind::LoadingFailed).into() + } +} + + +#[derive(Debug, Fail)] +pub enum OtherValidationError { + /// Non-multipart mail headers derive the Content-Type header from it's body `Resource`. + /// + /// This error is returned if a `Content-Type` header was given never the less. + #[fail(display = "Content-Type header given for non multipart mail")] + ContentTypeHeaderGiven, + + /// `Content-Transfer-Encoding` headers are always auto-generated + /// and can not be manually set. + #[fail(display = "Content-Transfer-Encoding header given")] + ContentTransferEncodingHeaderGiven, + + /// A non "multipart" media type was given as content type for a multipart mail. + #[fail(display = "found non multipart content type in multipart mail")] + SingleMultipartMixup, + + /// Inserting a `Conent-Type` header into a singlepart body is not allowed. + /// + /// In single-part bodies the `Content-Type` header is always auto-generated + /// based on the actual body. + #[fail(display = "inserting Content-Type for singlepart body is not allowed")] + InsertSinglepartContentTypeHeader, + + /// A multipart mail requires a `Content-Type` header to be given. + #[fail(display = "multipart mail does not contain a content type header")] + MissingContentTypeHeader, + + /// A mail (top level, not in multipart) requires a `From` header to be given. + #[fail(display = "mail did not contain a From header")] + NoFrom +} + +impl From<OtherValidationError> for HeaderValidationError { + fn from(oe: OtherValidationError) -> Self { + let err: ::failure::Error = oe.into(); + HeaderValidationError::Custom(err) + } +} + +impl From<OtherValidationError> for MailError { + fn from(oe: OtherValidationError) -> Self { + let val_err = HeaderValidationError::from(oe); + MailError::from(val_err) + } +} + +/// General Error combining most other error wrt. mail creation and encoding. +#[derive(Debug, Fail)] +pub enum MailError { + /// Encoding the mail failed. + #[fail(display = "{}", _0)] + Encoding(EncodingError), + + /// Different implementations for the same header where mixed up. + #[fail(display = "{}", _0)] + Type(HeaderTypeError), + + /// Creating a mail header body (component) failed. + #[fail(display = "{}", _0)] + Component(ComponentCreationError), + + /// The mail has some invalid header or header combinations. + /// + /// E.g. it has a `From` header with multiple mailboxes but no + /// `Sender` header (which is only required if `From` has more + /// than one mailbox). + #[fail(display = "{}", _0)] + Validation(HeaderValidationError), + + /// Loading an resource failed. + /// + /// E.g. the file to attach or the image to embedded could not + /// be found. + #[fail(display = "{}", _0)] + ResourceLoading(ResourceLoadingError) +} + +impl From<BuildInValidationError> for MailError { + fn from(err: BuildInValidationError) -> Self { + MailError::Validation(err.into()) + } +} + +impl From<HeaderTypeError> for MailError { + fn from(err: HeaderTypeError) -> Self { + MailError::Type(err) + } +} + +impl From<EncodingError> for MailError { + fn from(err: EncodingError) -> Self { + MailError::Encoding(err) + } +} + + +impl From<HeaderValidationError> for MailError { + fn from(err: HeaderValidationError) -> Self { + MailError::Validation(err) + } +} + +impl From<ResourceLoadingError> for MailError { + fn from(err: ResourceLoadingError) -> Self { + MailError::ResourceLoading(err) + } +} + +impl From<ResourceError> for MailError { + fn from(err: ResourceError) -> Self { + match err { + ResourceError::Loading(err) => MailError::ResourceLoading(err), + ResourceError::Encoding(err) => MailError::Encoding(err) + } + } +} + +impl From<ComponentCreationError> for MailError { + fn from(err: ComponentCreationError) -> Self { + MailError::Component(err) + } +} + + +/// Error returned when trying to _unload_ and `Resource` and it fails. +#[derive(Copy, Clone, Debug, Fail)] +pub enum ResourceNotUnloadableError { + /// The resource can not be unloaded because its in use. + #[fail(display = "resource is in use, can't unload it")] + InUse, + /// The resource can not be unloaded because it doesn't has a source. + /// + /// Which means if we would unload it we could not reload it. Note + /// that unloading is just for thinks like caching, it doesn't affect + /// the deletion/dropping of `Resource` instances. + #[fail(display = "resource has no source, can't unload it")] + NoSource +}
\ No newline at end of file |