Skip to content

Commit

Permalink
Implement HttpTryFrom<HashMap<String,String>> for HeaderMap
Browse files Browse the repository at this point in the history
This allows an easy conversion from HashMap<String,String>
to HeaderMap<HeaderValue>.

Doing this conversion used to be unnecessarily verbose
because of the required mapping and error type conversions.

The implementation is generic:

    impl<COLLECTION, K, V> HttpTryFrom<COLLECTION> for HeaderMap<HeaderValue>
    where
        COLLECTION: IntoIterator<Item=(K, V)>,
        K: AsRef<str>,
        V: AsRef<str>

so it also works for HashMap<HeaderName, String> and for vectors.

Fixes #325
  • Loading branch information
lovasoa committed Jul 2, 2019
1 parent 73002d2 commit d591131
Showing 1 changed file with 46 additions and 4 deletions.
50 changes: 46 additions & 4 deletions src/header/map.rs
@@ -1,5 +1,7 @@
use super::HeaderValue;
use super::name::{HeaderName, HdrName, InvalidHeaderName};
use crate::convert::HttpTryFrom;
use sealed::Sealed;

use std::{fmt, mem, ops, ptr, vec};
use std::collections::hash_map::RandomState;
Expand All @@ -23,10 +25,11 @@ pub use self::into_header_name::IntoHeaderName;
/// ```
/// # use http::HeaderMap;
/// # use http::header::{CONTENT_LENGTH, HOST, LOCATION};
/// let mut headers = HeaderMap::new();
///
/// headers.insert(HOST, "example.com".parse().unwrap());
/// headers.insert(CONTENT_LENGTH, "123".parse().unwrap());
/// # use http::HttpTryFrom;
/// let mut headers = HeaderMap::try_from(vec![
/// (HOST, "example.com"),
/// (CONTENT_LENGTH, "123")
/// ]).unwrap();
///
/// assert!(headers.contains_key(HOST));
/// assert!(!headers.contains_key(LOCATION));
Expand Down Expand Up @@ -1720,6 +1723,45 @@ impl<T> FromIterator<(HeaderName, T)> for HeaderMap<T>
}
}

impl<T> Sealed for HeaderMap<T> {}

/// Convert a collection of tuples into a HeaderMap
///
/// # Examples
///
/// ```
/// # use http::{HttpTryFrom, Result, header::HeaderMap};
/// # use std::collections::HashMap;
/// let mut headers_hashmap: HashMap<String, String> = vec![
/// ("X-Custom-Header".to_string(), "my value".to_string()),
/// ].iter().cloned().collect();
///
/// let good_headers: Result<HeaderMap> = HeaderMap::try_from(&headers_hashmap);
/// assert!(good_headers.is_ok());
///
/// headers_hashmap.insert("\r".into(), "\0".into());
/// let bad_headers: Result<HeaderMap> = HeaderMap::try_from(&headers_hashmap);
/// assert!(bad_headers.is_err());
/// ```
impl<COLLECTION, K, V> HttpTryFrom<COLLECTION> for HeaderMap<HeaderValue>
where
COLLECTION: IntoIterator<Item=(K, V)>,
K: AsRef<str>,
V: AsRef<str>
{
type Error = ::Error;

fn try_from(c: COLLECTION) -> Result<Self, Self::Error> {
c.into_iter()
.map(|(k, v)| -> ::Result<(HeaderName, HeaderValue)> {
let name = k.as_ref().parse()?;
let value = v.as_ref().parse()?;
Ok((name, value))
})
.collect()
}
}

impl<T> Extend<(Option<HeaderName>, T)> for HeaderMap<T> {
/// Extend a `HeaderMap` with the contents of another `HeaderMap`.
///
Expand Down

0 comments on commit d591131

Please sign in to comment.