use std::any::TypeId; use std::ops::{Deref, DerefMut}; use std::fmt::{self, Debug}; use internals::{ error::EncodingError, encoder::{ EncodableInHeader, EncodingWriter, } }; use ::error::ComponentCreationError; use ::convert::HeaderTryInto; use ::name::{HeaderName, HasHeaderName}; //NOTE: this is a circular dependency between Header/HeaderMap // but putting up e.g. a GenericHeaderMap trait/interface is // not worth the work at all use ::map::HeaderMapValidator; /// Trait representing a mail header. /// /// **This is not meant to be implemented by hand.*** /// Use the `def_headers` macro instead. /// pub trait HeaderKind: Clone + Default + 'static { /// the component representing the header-field, e.g. `Unstructured` for `Subject` type Component: EncodableInHeader + Clone; //FIXME[rust/const fn]: make this a associated constant /// a method returning the header name /// /// # Note: /// Once `const fn` is stable this will be changed to /// a associated constant. fn name() -> HeaderName; /// A function which is meant to be called with a reference /// to the final header map before encoding the headers. It is /// meant to be used do some of the contextual validations, /// like e.g. a `From` header might return a function which /// checks if the `From` header has multiple mailboxes and /// if so checks if there is a `Sender` header /// /// Calling a contextual validator with a header map not /// containing a header which it is meant to validate /// should not cause an error. Only if the header is /// there and the component is of the expected type /// and it is invalid in the context /// an error should be returned. const VALIDATOR: Option; /// I true this will assure that the header is at most one time in a header map. /// /// This is similar to `VALIDATOR` (and can be archived through one) but in difference /// to any `VALIDATOR` this is already assured when inserting a header with MAX_ONE set /// to true in a header map. It exists so that the header map can do, what is most /// intuitive, replacing insertion for all `MAX_ONE` headers (like in a normal map) but /// use adding insertion for all other header (like in a multi map). /// /// Most headers have this set to true. const MAX_ONE: bool; /// Creates a `Header` instance automatically converting given body to the right type. /// /// # Error /// /// The type system assure that you can only use it on conversions /// which are possible on type level, but they can still fail depending /// on the actual data. For example creating a `Email` from a string /// can fail if the string is not a valid email address. This in /// turn means that creating a `From` header from a array of strings /// can fail if one of them is not a valid email address. fn auto_body(body: H) -> Result, ComponentCreationError> where H: HeaderTryInto { Ok(Self::body(HeaderTryInto::try_into(body)?)) } /// Creates a `Header` instance for this header kind with given body. fn body(body: Self::Component) -> Header { Header::new(body) } } impl HasHeaderName for H where H: HeaderKind { fn get_name(&self) -> HeaderName { H::name() } } pub trait MaxOneMarker: HeaderKind {} #[derive(Clone)] pub struct Header where H: HeaderKind { body: H::Component } impl Header where H: HeaderKind { pub fn new(body: H::Component) -> Header { Header { body } } pub fn body(&self) -> &H::Component { &self.body } pub fn body_mut(&mut self) -> &mut H::Component { &mut self.body } } impl Deref for Header where H: HeaderKind { type Target = H::Component; fn deref(&self) -> &Self::Target { self.body() } } impl DerefMut for Header where H: HeaderKind { fn deref_mut(&mut self) -> &mut Self::Target { self.body_mut() } } impl Debug for Header where H: HeaderKind { fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result { self.body.fmt(fter) } } /// Type alias for HeaderObjTrait's trait object. pub type HeaderObj = dyn HeaderObjTrait; pub trait HeaderObjTrait: Sync + Send + ::std::any::Any + Debug { fn name(&self) -> HeaderName; fn is_max_one(&self) -> bool; fn validator(&self) -> Option; fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError>; fn boxed_clone(&self) -> Box; #[doc(hidden)] fn type_id(&self) -> TypeId { TypeId::of::() } } impl HeaderObjTrait for Header where H: HeaderKind { fn name(&self) -> HeaderName { H::name() } fn is_max_one(&self) -> bool { H::MAX_ONE } fn validator(&self) -> Option { H::VALIDATOR } fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError> { self.body.encode(encoder) } fn boxed_clone(&self) -> Box { let cloned = self.clone(); Box::new(cloned) } } impl HasHeaderName for Header where H: HeaderKind { fn get_name(&self) -> HeaderName { H::name() } } impl HeaderObj { pub fn is(&self) -> bool where H: HeaderKind { HeaderObjTrait::type_id(self) == TypeId::of::>() } pub fn downcast_ref(&self) -> Option<&Header> where H: HeaderKind { if self.is::() { Some(unsafe { &*(self as *const _ as *const Header) }) } else { None } } pub fn downcast_mut(&mut self) -> Option<&mut Header> where H: HeaderKind { if self.is::() { Some(unsafe { &mut *(self as *mut _ as *mut Header) }) } else { None } } } impl Clone for Box { fn clone(&self) -> Self { self.boxed_clone() } } impl HasHeaderName for HeaderObj { fn get_name(&self) -> HeaderName { self.name() } } pub trait HeaderObjTraitBoxExt: Sized { fn downcast(self) -> Result>, Self> where H: HeaderKind; } impl HeaderObjTraitBoxExt for Box { fn downcast(self) -> Result>, Self> where H: HeaderKind { if HeaderObjTrait::is::(&*self) { let ptr: *mut (HeaderObj) = Box::into_raw(self); Ok(unsafe { Box::from_raw(ptr as *mut Header) }) } else { Err(self) } } }