Struct mail_headers::map::HeaderMap
source · pub struct HeaderMap { /* private fields */ }
Expand description
A header map is a collection representing a number of mail headers in an specific order.
Example
// just import all headers
use mail_headers::HeaderMap;
use mail_headers::headers::*;
use mail_headers::error::ComponentCreationError;
fn create_headers() -> Result<HeaderMap, ComponentCreationError> {
headers!{
// from and to can have multiple values
// until specialization is stable is array
// is necessary
_From: [("My Fancy Display Name", "theduck@example.com")],
_To: [ "unknown@example.com", ],
Subject: "Who are you?"
}
}
fn main() {
let headers = create_headers().unwrap();
assert_eq!(headers.len(), 3);
}
Note
A number of methods implemented on HeaderMap appear in two variations,
one which accepts a type hint (a normally zero sized struct implementing
HeaderKind) and on which just accepts the type and needs to be called with
the turbofish operator. The later one is prefixed by a _
as the former
one is more nice to use, but in some situations, e.g. when wrapping
HeaderMap
in custom code the only type accepting variations are more
useful.
let _ = map.get(Subject);
//is equivalent to
let _ = map._get::<Subject>();
MaxOne (In-)Consistency
Most headers can only appear up to one time in a header section.
They are marked with H::MAX_ONE == true
and implement MaxOneMarker
,
also as object you can use is_max_one
to check it.
Not only can they only appear max one time, it is normal for a user
who is not aware about the other headers to expect that when you insert
them into a header map which already contains them that they replace
the existing header. Even more so most headers which can appear more
then one time are unlikely to appear in a application of this library
like e.g. all Resent-*
header which normally get just prepended
to existing mail in text format or the Comment
header which isn’t
used that much.
Because of this it was decided that when inserting a "max one"
header
it will act as expected an replace other headers with the same name and
only if a "multi"
header is inserted it is added to all headers associated
with the same name.
But there is a single problem. If there are multiple implementations implementations
for the same header which disagree in wether or not the header is "max one"
(which
would be a bug anyway!) then this can lead to a tricky situration when you first
insert the version which is "max one"
and then the one which is "multi"
.
There had been two ways to deal with this:
- return a error when inserting in such a situation
- simple allow it and check it when running the other validators
Given that a header map contains additionally validators which needs to be run explicitly to make sure that a map is valid before using it as a header section in a mail it was decided to go with the later approach. Originally the first approach was implemented but turned out to be not very ergonomic, and the second approach has little disadvantages as:
- it’s already unlikely to run into the situation
- you have to run validators anyway before using the header map
So yes, you can not relay on the “max one” constraints to be uphold without running the validators
Implementations
sourceimpl HeaderMap
impl HeaderMap
sourcepub fn values_mut(&mut self) -> ValuesMut<'_>
pub fn values_mut(&mut self) -> ValuesMut<'_>
Iterate with mut refs over all HeaderObj
added to the map.
sourcepub fn use_contextual_validators(&self) -> Result<(), HeaderValidationError>
pub fn use_contextual_validators(&self) -> Result<(), HeaderValidationError>
call each unique contextual validator exactly once with this map as parameter
If multiple Headers provide the same contextual validator (e.g. the resent headers) it’s still only called once.
Max One
This will also validate that for any header name for which a header
was added with MAX_ONE == true
it will be validated that it is the
only header for that header name.
sourcepub fn contains<H: HasHeaderName>(&self, name: H) -> bool
pub fn contains<H: HasHeaderName>(&self, name: H) -> bool
Returns true if this map contains a header with the given name.
sourcepub fn get_single<'a, H>(
&'a self,
_type_hint: H
) -> Option<Result<&'a Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
pub fn get_single<'a, H>(
&'a self,
_type_hint: H
) -> Option<Result<&'a Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
Returns the single header associated with the given header kind.
As this uses the MaxOneMarker
trait which should only be implemented
for HeaderKind
impl with MAX_ONE == true
this function can only
be used when it’s fine to ignore the possible case of more than
one header of the given kind being in the same map.
Type Hint
The type hint passed in is for ergonomics, e.g. so
that it’s possible to write code like map.get_single(Subject)
if this gets in the way _get_single
can be used which would
lead to code like map._get_single::<Subject>()
.
Error
-
If there are multiple implementations for the same header and the inserted headers is based on a different type some
HeaderTypeError
is returned -
If there are multiple implementations for the same header which disagree on the value of
H::MAX_ONE
(which is a bug) this can in some rare situations lead to be there more then one header for a “max one” header in the map, in which case aHeaderTypeError
is returned.
sourcepub fn _get_single<'a, H>(
&'a self
) -> Option<Result<&'a Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
pub fn _get_single<'a, H>(
&'a self
) -> Option<Result<&'a Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
A variation of get_single
which doesn’t require passing in a type hint.
Normally using get_single
is more ergonomic, except if you write a function
which abstracts over it in which case using _get_single
can be better.
sourcepub fn get_single_mut<H>(
&mut self,
_type_hint: H
) -> Option<Result<&mut Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
pub fn get_single_mut<H>(
&mut self,
_type_hint: H
) -> Option<Result<&mut Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
Returns a a mutable reference to the header associated with the given header kind.__internals
See HeaderMap::get_single
for more details.
sourcepub fn _get_single_mut<H>(
&mut self
) -> Option<Result<&mut Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
pub fn _get_single_mut<H>(
&mut self
) -> Option<Result<&mut Header<H>, HeaderTypeError>>where
H: MaxOneMarker,
Returns a a mutable reference to the header associated with the given header kind.__internals
See HeaderMap::_get_single
for more details.
sourcepub fn get_untyped<H: HasHeaderName>(&self, name: H) -> UntypedBodies<'_>
pub fn get_untyped<H: HasHeaderName>(&self, name: H) -> UntypedBodies<'_>
Returns all header bodies for a given header name, without trying to cast them to a concrete type
Accepts both HeaderName
or a type implementing HeaderKind
.
sourcepub fn get_untyped_mut<H: HasHeaderName>(
&mut self,
name: H
) -> UntypedBodiesMut<'_>
pub fn get_untyped_mut<H: HasHeaderName>(
&mut self,
name: H
) -> UntypedBodiesMut<'_>
Returns all header bodies for a given header name, without trying to cast them to a concrete type
Accepts both HeaderName
or a type implementing HeaderKind
.
sourcepub fn get<H>(&self, _type_hint: H) -> TypedBodies<'_, H> ⓘwhere
H: HeaderKind,
pub fn get<H>(&self, _type_hint: H) -> TypedBodies<'_, H> ⓘwhere
H: HeaderKind,
Returns all header bodies for a given header
sourcepub fn _get<H>(&self) -> TypedBodies<'_, H> ⓘwhere
H: HeaderKind,
pub fn _get<H>(&self) -> TypedBodies<'_, H> ⓘwhere
H: HeaderKind,
Returns all header bodies for a given header
sourcepub fn get_mut<H>(&mut self, _type_hint: H) -> TypedBodiesMut<'_, H> ⓘwhere
H: HeaderKind,
pub fn get_mut<H>(&mut self, _type_hint: H) -> TypedBodiesMut<'_, H> ⓘwhere
H: HeaderKind,
Returns all header bodies for a given header
sourcepub fn _get_mut<H>(&mut self) -> TypedBodiesMut<'_, H> ⓘwhere
H: HeaderKind,
pub fn _get_mut<H>(&mut self) -> TypedBodiesMut<'_, H> ⓘwhere
H: HeaderKind,
Returns all header bodies for a given header
sourcepub fn insert<H>(&mut self, header: Header<H>)where
H: HeaderKind,
pub fn insert<H>(&mut self, header: Header<H>)where
H: HeaderKind,
Inserts the given header into the map either replacing or adding to existing headers.
-
If
H::MAX_ONE
istrue
then it will use “replacing insert” which means all headers previously associated with the given header (name) are removed when adding the new header.This behavior is analog to how a normal map works and is what a user which isn’t aware that there are some headers which can appear multiple times would expect. Most common headers (
Subject
,From
,To
,Sender
, etc.) fall into this category. -
If
H::MAX_ONE
isfalse
then it will use “adding insert” which means that it will add the header to all headers previously associated with the given header name.
sourcepub fn insert_all(&mut self, other: HeaderMap)
pub fn insert_all(&mut self, other: HeaderMap)
Insert all given headers in order into this header map.
The insertion order of the given headers into this map is the same as the order in which they had been inserted into the header map through which they had been given to this method.
As this uses insertion it also means that headers with
MAX_ONE == true
in the headers to insert can replace
existing headers associated with the same header name.
Example
use mail_headers::headers::*;
let mut map = headers!{
_From: [("Not Met", "it.s.me@example.com")],
Subject: "..."
}.unwrap();
map.insert_all(headers! {
_To: [("You", "someone@example.com")],
Subject: "expected subject"
}.unwrap());
assert_eq!(map.len(), 3);
let subject = map.get_single(Subject)
.expect("Subject to be in map (Some)")
.expect("The type to be correct (Ok)");
assert_eq!(subject.as_str(), "expected subject");
assert!(map.contains(_From));
assert!(map.contains(_To));
sourcepub fn remove<H: HasHeaderName>(&mut self, name: H) -> bool
pub fn remove<H: HasHeaderName>(&mut self, name: H) -> bool
Remove all headers with the given header name.
Returns true, if at last one header was removed.