1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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<HeaderMapValidator>;

    /// 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<H>(body: H) -> Result<Header<Self>, ComponentCreationError>
        where H: HeaderTryInto<Self::Component>
    {
        Ok(Self::body(HeaderTryInto::try_into(body)?))
    }

    /// Creates a `Header` instance for this header kind with given body.
    fn body(body: Self::Component) -> Header<Self> {
        Header::new(body)
    }
}

impl<H> HasHeaderName for H
    where H: HeaderKind
{
    fn get_name(&self) -> HeaderName {
        H::name()
    }
}

pub trait MaxOneMarker: HeaderKind {}

#[derive(Clone)]
pub struct Header<H>
    where H: HeaderKind
{
    body: H::Component
}

impl<H> Header<H>
    where H: HeaderKind
{
    pub fn new(body: H::Component) -> Header<H> {
        Header { body }
    }

    pub fn body(&self) -> &H::Component {
        &self.body
    }

    pub fn body_mut(&mut self) -> &mut H::Component {
        &mut self.body
    }
}

impl<H> Deref for Header<H>
    where H: HeaderKind
{
    type Target = H::Component;
    fn deref(&self) -> &Self::Target {
        self.body()
    }
}

impl<H> DerefMut for Header<H>
    where H: HeaderKind
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.body_mut()
    }
}

impl<H> Debug for Header<H>
    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<HeaderMapValidator>;
    fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError>;
    fn boxed_clone(&self) -> Box<HeaderObj>;

    #[doc(hidden)]
    fn type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }
}

impl<H> HeaderObjTrait for Header<H>
    where H: HeaderKind
{
    fn name(&self) -> HeaderName {
        H::name()
    }

    fn is_max_one(&self) -> bool {
        H::MAX_ONE
    }

    fn validator(&self) -> Option<HeaderMapValidator> {
        H::VALIDATOR
    }

    fn encode(&self, encoder: &mut EncodingWriter) -> Result<(), EncodingError> {
        self.body.encode(encoder)
    }

    fn boxed_clone(&self) -> Box<HeaderObj> {
        let cloned = self.clone();
        Box::new(cloned)
    }
}

impl<H> HasHeaderName for Header<H>
    where H: HeaderKind
{
    fn get_name(&self) -> HeaderName {
        H::name()
    }
}


impl HeaderObj {
    pub fn is<H>(&self) -> bool
        where H: HeaderKind
    {
        HeaderObjTrait::type_id(self) == TypeId::of::<Header<H>>()
    }

    pub fn downcast_ref<H>(&self) -> Option<&Header<H>>
        where H: HeaderKind
    {
        if self.is::<H>() {
            Some(unsafe { &*(self as *const _ as *const Header<H>) })
        } else {
            None
        }
    }

    pub fn downcast_mut<H>(&mut self) -> Option<&mut Header<H>>
        where H: HeaderKind
    {
        if self.is::<H>() {
            Some(unsafe { &mut *(self as *mut _ as *mut Header<H>) })
        } else {
            None
        }
    }
}

impl Clone for Box<HeaderObj> {
    fn clone(&self) -> Self {
        self.boxed_clone()
    }
}

impl HasHeaderName for HeaderObj {
    fn get_name(&self) -> HeaderName {
        self.name()
    }
}

pub trait HeaderObjTraitBoxExt: Sized {
    fn downcast<H>(self) -> Result<Box<Header<H>>, Self>
        where H: HeaderKind;
}

impl HeaderObjTraitBoxExt for Box<HeaderObjTrait> {

    fn downcast<H>(self) -> Result<Box<Header<H>>, Self>
        where H: HeaderKind
    {
        if HeaderObjTrait::is::<H>(&*self) {
            let ptr: *mut (HeaderObj) = Box::into_raw(self);
            Ok(unsafe { Box::from_raw(ptr as *mut Header<H>) })
        } else {
            Err(self)
        }
    }
}