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:

  1. return a error when inserting in such a situation
  2. 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

create a new empty header map

returns the number of headers in this map

clears the header map

This removes all headers and all validators

Iterate over all HeaderObj added to the map.

Iterate with mut refs over all HeaderObj added to the map.

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.

Returns true if this map contains a header with the given name.

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 a HeaderTypeError is returned.

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.

Returns a a mutable reference to the header associated with the given header kind.__internals

See HeaderMap::get_single for more details.

Returns a a mutable reference to the header associated with the given header kind.__internals

See HeaderMap::_get_single for more details.

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.

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.

Returns all header bodies for a given header

Returns all header bodies for a given header

Returns all header bodies for a given header

Returns all header bodies for a given header

Inserts the given header into the map either replacing or adding to existing headers.

  • If H::MAX_ONE is true 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 is false then it will use “adding insert” which means that it will add the header to all headers previously associated with the given header name.

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));

Remove all headers with the given header name.

Returns true, if at last one header was removed.

iterate over all (header name, boxed body) pairs in this map

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
The type of the elements being iterated over.
Which kind of iterator are we turning this into?
Creates an iterator from a value. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.