move HeaderMap function implementation to trait
This commit is contained in:
+167
-43
@@ -3,71 +3,129 @@ use mailparse::MailHeader;
|
|||||||
use super::{Header, build_header};
|
use super::{Header, build_header};
|
||||||
use crate::{CowMailError, extend_over_newline};
|
use crate::{CowMailError, extend_over_newline};
|
||||||
|
|
||||||
|
/// Find, iterate and edit a collection of headers by key.
|
||||||
|
///
|
||||||
|
/// Implementors only have to hand out their headers; everything else is
|
||||||
|
/// provided. Keys match case-insensitively throughout, and an `index` argument
|
||||||
|
/// counts occurrences of `key`, not positions in the collection.
|
||||||
pub trait HeaderMap<'a, H: Header<'a> + 'a> {
|
pub trait HeaderMap<'a, H: Header<'a> + 'a> {
|
||||||
fn iter_headers(&'a self, key: &str) -> impl Iterator<Item = &'a H>;
|
/// The headers, in the order they appear in the message.
|
||||||
fn iter_headers_mut(&'a mut self, key: &str) -> impl Iterator<Item = &'a mut H>;
|
fn headers(&self) -> &[H];
|
||||||
fn iter_values(&'a self, key: &str) -> impl Iterator<Item = String>;
|
|
||||||
fn find_header(&self, key: &str) -> Option<&H>;
|
/// The headers, mutably. A `Vec` rather than a slice, because inserting and
|
||||||
fn find_header_mut(&mut self, key: &str) -> Option<&mut H>;
|
/// removing go through it.
|
||||||
fn find_value(&self, key: &str) -> Option<String>;
|
fn headers_mut(&mut self) -> &mut Vec<H>;
|
||||||
fn add_header<K: ToString, V: ToString>(&mut self, key: K, value: V);
|
|
||||||
fn insert_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize);
|
fn iter_headers<'b>(&'b self, key: &str) -> impl Iterator<Item = &'b H>
|
||||||
fn replace_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize);
|
where
|
||||||
fn replace_all_headers<K: ToString, V: ToString>(&mut self, key: K, value: V);
|
H: 'b,
|
||||||
fn remove_header(&mut self, key: &str, index: usize);
|
{
|
||||||
fn remove_all_headers(&mut self, key: &str);
|
self.headers().iter().filter(move |h| h.key_eq(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H: Header<'a> + 'a> HeaderMap<'a, H> for Vec<H> {
|
fn iter_headers_mut<'b>(&'b mut self, key: &str) -> impl Iterator<Item = &'b mut H>
|
||||||
fn iter_headers(&'a self, key: &str) -> impl Iterator<Item = &'a H> {
|
where
|
||||||
self.iter().filter(|h| h.key_eq(key))
|
H: 'b,
|
||||||
|
{
|
||||||
|
self.headers_mut().iter_mut().filter(move |h| h.key_eq(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_headers_mut(&'a mut self, key: &str) -> impl Iterator<Item = &'a mut H> {
|
/// Examples
|
||||||
self.iter_mut()
|
/// ```
|
||||||
.filter(|h| h.key_eq(key))
|
/// use email_message::{CowMail, HeaderMap};
|
||||||
}
|
/// let mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test\n",
|
||||||
fn iter_values(&'a self, key: &str) -> impl Iterator<Item = String> {
|
/// "Subject: Test1\n",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// let mut values = mail.iter_values("Subject");
|
||||||
|
/// assert_eq!(values.next().unwrap(), "Test");
|
||||||
|
/// assert_eq!(values.next().unwrap(), "Test1");
|
||||||
|
/// assert!(values.next().is_none());
|
||||||
|
/// ```
|
||||||
|
fn iter_values<'b>(&'b self, key: &str) -> impl Iterator<Item = String>
|
||||||
|
where
|
||||||
|
H: 'b,
|
||||||
|
{
|
||||||
self.iter_headers(key).map(|h| h.get_value())
|
self.iter_headers(key).map(|h| h.get_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_header(&self, key: &str) -> Option<&H> {
|
fn find_header(&self, key: &str) -> Option<&H> {
|
||||||
self.iter().find(|h| h.key_eq(key))
|
self.headers().iter().find(|h| h.key_eq(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_header_mut(&mut self, key: &str) -> Option<&mut H> {
|
fn find_header_mut(&mut self, key: &str) -> Option<&mut H> {
|
||||||
self.iter_mut().find(|h| h.key_eq(key))
|
self.headers_mut().iter_mut().find(|h| h.key_eq(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Examples
|
||||||
|
/// ```
|
||||||
|
/// use email_message::{CowMail, HeaderMap};
|
||||||
|
/// let mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test\n",
|
||||||
|
/// "Subject: Test1",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// assert_eq!(mail.find_value("Subject").unwrap(), "Test");
|
||||||
|
/// ```
|
||||||
fn find_value(&self, key: &str) -> Option<String> {
|
fn find_value(&self, key: &str) -> Option<String> {
|
||||||
self.find_header(key).map(|h| h.get_value())
|
self.find_header(key).map(|h| h.get_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Examples
|
||||||
|
/// ```
|
||||||
|
/// use email_message::{CowMail, HeaderMap};
|
||||||
|
/// let mut mail = CowMail::default();
|
||||||
|
/// mail.add_header("Subject", "Test");
|
||||||
|
/// assert_eq!(mail.find_value("Subject").unwrap(), "Test");
|
||||||
|
/// ```
|
||||||
fn add_header<K: ToString, V: ToString>(&mut self, key: K, value: V) {
|
fn add_header<K: ToString, V: ToString>(&mut self, key: K, value: V) {
|
||||||
self.push(H::new(key, value))
|
self.headers_mut().push(H::new(key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Examples
|
||||||
|
/// ```
|
||||||
|
/// use email_message::{CowMail, Header, HeaderMap};
|
||||||
|
/// let mut mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test\n",
|
||||||
|
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// mail.insert_header("From", "\"me\" <me@example.com>", 1);
|
||||||
|
/// assert_eq!(mail.headers[0].get_key(), "Subject");
|
||||||
|
/// assert_eq!(mail.headers[1].get_key(), "From");
|
||||||
|
/// assert_eq!(mail.headers[2].get_key(), "To");
|
||||||
|
/// ```
|
||||||
fn insert_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize) {
|
fn insert_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize) {
|
||||||
let index = std::cmp::min(index, self.len());
|
let headers = self.headers_mut();
|
||||||
|
let index = std::cmp::min(index, headers.len());
|
||||||
let header = H::new(key, value);
|
let header = H::new(key, value);
|
||||||
self.insert(index, header);
|
headers.insert(index, header);
|
||||||
}
|
|
||||||
|
|
||||||
fn replace_all_headers<K: ToString, V: ToString>(&mut self, key: K, value: V) {
|
|
||||||
let key = key.to_string();
|
|
||||||
for header in self {
|
|
||||||
if !header.get_key().eq_ignore_ascii_case(&key) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
header.set_value(value.to_string());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Examples
|
||||||
|
/// ```
|
||||||
|
/// use email_message::{CowMail, Header, HeaderMap};
|
||||||
|
/// let mut mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test1\n",
|
||||||
|
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
||||||
|
/// "Subject: Test2\n",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// mail.replace_header("Subject", "Test3", 0);
|
||||||
|
/// mail.replace_header("Subject", "Test4", 1);
|
||||||
|
/// assert_eq!(mail.headers[0].get_value_ref(), "Test3");
|
||||||
|
/// assert_eq!(mail.headers[1].get_value_ref(), "\"John Doe\" <john.doe@example.com>");
|
||||||
|
/// assert_eq!(mail.headers[2].get_value_ref(), "Test4");
|
||||||
|
/// ```
|
||||||
fn replace_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize) {
|
fn replace_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize) {
|
||||||
let key = key.to_string();
|
let key = key.to_string();
|
||||||
let mut count: usize = 0;
|
let mut count: usize = 0;
|
||||||
for header in self {
|
for header in self.headers_mut() {
|
||||||
if !header.get_key().eq_ignore_ascii_case(&key) {
|
if !header.get_key().eq_ignore_ascii_case(&key) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -79,20 +137,86 @@ impl<'a, H: Header<'a> + 'a> HeaderMap<'a, H> for Vec<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_all_headers(&mut self, key: &str) {
|
/// Examples
|
||||||
self.retain(|h| !h.key_eq(key));
|
/// ```
|
||||||
|
/// use email_message::{CowMail, Header, HeaderMap};
|
||||||
|
/// let mut mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test\n",
|
||||||
|
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
||||||
|
/// "Subject: Test1\n",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// mail.replace_all_headers("Subject", "Test2");
|
||||||
|
/// assert_eq!(mail.headers[0].get_value_ref(), "Test2");
|
||||||
|
/// assert_eq!(mail.headers[1].get_value_ref(), "\"John Doe\" <john.doe@example.com>");
|
||||||
|
/// assert_eq!(mail.headers[2].get_value_ref(), "Test2");
|
||||||
|
/// ```
|
||||||
|
fn replace_all_headers<K: ToString, V: ToString>(&mut self, key: K, value: V) {
|
||||||
|
let key = key.to_string();
|
||||||
|
for header in self.headers_mut() {
|
||||||
|
if !header.get_key().eq_ignore_ascii_case(&key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
header.set_value(value.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Examples
|
||||||
|
/// ```
|
||||||
|
/// use email_message::{CowMail, Header, HeaderMap};
|
||||||
|
/// let mut mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test1\n",
|
||||||
|
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
||||||
|
/// "Subject: Test2\n",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// mail.remove_header("Subject", 1);
|
||||||
|
/// assert_eq!(mail.headers.len(), 2);
|
||||||
|
/// assert_eq!(mail.headers[0].get_value_ref(), "Test1");
|
||||||
|
/// ```
|
||||||
fn remove_header(&mut self, key: &str, index: usize) {
|
fn remove_header(&mut self, key: &str, index: usize) {
|
||||||
if let Some((index, _)) = self
|
let found = self
|
||||||
|
.headers()
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter(move |h| h.1.key_eq(key))
|
.filter(|h| h.1.key_eq(key))
|
||||||
.nth(index)
|
.nth(index)
|
||||||
{
|
.map(|(index, _)| index);
|
||||||
self.remove(index);
|
|
||||||
|
if let Some(index) = found {
|
||||||
|
self.headers_mut().remove(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Examples
|
||||||
|
/// ```
|
||||||
|
/// use email_message::{CowMail, Header, HeaderMap};
|
||||||
|
/// let mut mail = CowMail::try_from(concat!(
|
||||||
|
/// "Subject: Test1\n",
|
||||||
|
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
||||||
|
/// "Subject: Test2\n",
|
||||||
|
/// "\n",
|
||||||
|
/// "This is a test message").as_bytes())
|
||||||
|
/// .unwrap();
|
||||||
|
/// mail.remove_all_headers("Subject");
|
||||||
|
/// assert_eq!(mail.headers.len(), 1);
|
||||||
|
/// assert_eq!(mail.headers[0].get_value_ref(), "\"John Doe\" <john.doe@example.com>");
|
||||||
|
/// ```
|
||||||
|
fn remove_all_headers(&mut self, key: &str) {
|
||||||
|
self.headers_mut().retain(|h| !h.key_eq(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, H: Header<'a> + 'a> HeaderMap<'a, H> for Vec<H> {
|
||||||
|
fn headers(&self) -> &[H] {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn headers_mut(&mut self) -> &mut Vec<H> {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rebuild the header lines mailparse has already scanned, so that a part's
|
/// Rebuild the header lines mailparse has already scanned, so that a part's
|
||||||
|
|||||||
+4
-149
@@ -666,157 +666,12 @@ impl<'a, H: Header<'a> + 'a> CowMail<'a, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H: Header<'a> + 'a> HeaderMap<'a, H> for CowMail<'a, H> {
|
impl<'a, H: Header<'a> + 'a> HeaderMap<'a, H> for CowMail<'a, H> {
|
||||||
fn iter_headers(&'a self, key: &str) -> impl Iterator<Item = &'a H> {
|
fn headers(&self) -> &[H] {
|
||||||
self.headers.iter_headers(key)
|
&self.headers
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_headers_mut(&'a mut self, key: &str) -> impl Iterator<Item = &'a mut H> {
|
fn headers_mut(&mut self) -> &mut Vec<H> {
|
||||||
self.headers.iter_headers_mut(key)
|
&mut self.headers
|
||||||
}
|
|
||||||
|
|
||||||
fn find_header(&self, key: &str) -> Option<&H> {
|
|
||||||
self.headers.find_header(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_header_mut(&mut self, key: &str) -> Option<&mut H> {
|
|
||||||
self.headers.find_header_mut(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, HeaderMap};
|
|
||||||
/// let mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test\n",
|
|
||||||
/// "Subject: Test1\n",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// let mut values = mail.iter_values("Subject");
|
|
||||||
/// assert_eq!(values.next().unwrap(), "Test");
|
|
||||||
/// assert_eq!(values.next().unwrap(), "Test1");
|
|
||||||
/// assert!(values.next().is_none());
|
|
||||||
/// ```
|
|
||||||
fn iter_values(&'a self, key: &str) -> impl Iterator<Item = String> {
|
|
||||||
self.headers.iter_values(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, HeaderMap};
|
|
||||||
/// let mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test\n",
|
|
||||||
/// "Subject: Test1",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// assert_eq!(mail.find_value("Subject").unwrap(), "Test");
|
|
||||||
/// ```
|
|
||||||
fn find_value(&self, key: &str) -> Option<String> {
|
|
||||||
self.headers.find_value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, HeaderMap};
|
|
||||||
/// let mut mail = CowMail::default();
|
|
||||||
/// mail.add_header("Subject", "Test");
|
|
||||||
/// assert_eq!(mail.find_value("Subject").unwrap(), "Test");
|
|
||||||
/// ```
|
|
||||||
fn add_header<K: ToString, V: ToString>(&mut self, key: K, value: V) {
|
|
||||||
self.headers.add_header(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, Header, HeaderMap};
|
|
||||||
/// let mut mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test\n",
|
|
||||||
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// mail.insert_header("From", "\"me\" <me@example.com>", 1);
|
|
||||||
/// assert_eq!(mail.headers[0].get_key(), "Subject");
|
|
||||||
/// assert_eq!(mail.headers[1].get_key(), "From");
|
|
||||||
/// assert_eq!(mail.headers[2].get_key(), "To");
|
|
||||||
/// ```
|
|
||||||
fn insert_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize) {
|
|
||||||
self.headers.insert_header(key, value, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, Header, HeaderMap};
|
|
||||||
/// let mut mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test\n",
|
|
||||||
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
|
||||||
/// "Subject: Test1\n",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// mail.replace_all_headers("Subject", "Test2");
|
|
||||||
/// assert_eq!(mail.headers[0].get_value_ref(), "Test2");
|
|
||||||
/// assert_eq!(mail.headers[1].get_value_ref(), "\"John Doe\" <john.doe@example.com>");
|
|
||||||
/// assert_eq!(mail.headers[2].get_value_ref(), "Test2");
|
|
||||||
/// ```
|
|
||||||
fn replace_all_headers<K: ToString, V: ToString>(&mut self, key: K, value: V) {
|
|
||||||
self.headers.replace_all_headers(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, Header, HeaderMap};
|
|
||||||
/// let mut mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test1\n",
|
|
||||||
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
|
||||||
/// "Subject: Test2\n",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// mail.replace_header("Subject", "Test3", 0);
|
|
||||||
/// mail.replace_header("Subject", "Test4", 1);
|
|
||||||
/// assert_eq!(mail.headers[0].get_value_ref(), "Test3");
|
|
||||||
/// assert_eq!(mail.headers[1].get_value_ref(), "\"John Doe\" <john.doe@example.com>");
|
|
||||||
/// assert_eq!(mail.headers[2].get_value_ref(), "Test4");
|
|
||||||
/// ```
|
|
||||||
fn replace_header<K: ToString, V: ToString>(&mut self, key: K, value: V, index: usize) {
|
|
||||||
self.headers.replace_header(key, value, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, Header, HeaderMap};
|
|
||||||
/// let mut mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test1\n",
|
|
||||||
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
|
||||||
/// "Subject: Test2\n",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// mail.remove_all_headers("Subject");
|
|
||||||
/// assert_eq!(mail.headers.len(), 1);
|
|
||||||
/// assert_eq!(mail.headers[0].get_value_ref(), "\"John Doe\" <john.doe@example.com>");
|
|
||||||
/// ```
|
|
||||||
fn remove_all_headers(&mut self, key: &str) {
|
|
||||||
self.headers.remove_all_headers(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Examples
|
|
||||||
/// ```
|
|
||||||
/// use email_message::{CowMail, Header, HeaderMap};
|
|
||||||
/// let mut mail = CowMail::try_from(concat!(
|
|
||||||
/// "Subject: Test1\n",
|
|
||||||
/// "To: \"John Doe\" <john.doe@example.com>\n",
|
|
||||||
/// "Subject: Test2\n",
|
|
||||||
/// "\n",
|
|
||||||
/// "This is a test message").as_bytes())
|
|
||||||
/// .unwrap();
|
|
||||||
/// mail.remove_header("Subject", 1);
|
|
||||||
/// assert_eq!(mail.headers.len(), 2);
|
|
||||||
/// assert_eq!(mail.headers[0].get_value_ref(), "Test1");
|
|
||||||
/// ```
|
|
||||||
fn remove_header(&mut self, key: &str, index: usize) {
|
|
||||||
self.headers.remove_header(key, index)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user