Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement HttpTryFrom<HashMap<String,String>> for HeaderMap #326

Merged
merged 8 commits into from Jul 25, 2019
3 changes: 2 additions & 1 deletion src/convert.rs
@@ -1,5 +1,5 @@
use Error;
use header::{HeaderName, HeaderValue};
use header::{HeaderName, HeaderValue, HeaderMap};
use method::Method;
use sealed::Sealed;
use status::StatusCode;
Expand Down Expand Up @@ -56,6 +56,7 @@ reflexive! {
Uri,
Method,
StatusCode,
HeaderMap,
HeaderName,
HeaderValue,
Scheme,
Expand Down
51 changes: 46 additions & 5 deletions src/header/map.rs
@@ -1,12 +1,16 @@
use super::HeaderValue;
use super::name::{HeaderName, HdrName, InvalidHeaderName};

use std::{fmt, mem, ops, ptr, vec};
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hasher, Hash};
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash, Hasher};
use std::iter::FromIterator;
use std::marker::PhantomData;

use convert::{HttpTryFrom, HttpTryInto};
use Error;

use super::HeaderValue;
use super::name::{HdrName, HeaderName, InvalidHeaderName};

pub use self::as_header_name::AsHeaderName;
pub use self::into_header_name::IntoHeaderName;

Expand All @@ -23,6 +27,7 @@ pub use self::into_header_name::IntoHeaderName;
/// ```
/// # use http::HeaderMap;
/// # use http::header::{CONTENT_LENGTH, HOST, LOCATION};
/// # use http::HttpTryFrom;
seanmonstar marked this conversation as resolved.
Show resolved Hide resolved
/// let mut headers = HeaderMap::new();
///
/// headers.insert(HOST, "example.com".parse().unwrap());
Expand Down Expand Up @@ -1720,6 +1725,42 @@ impl<T> FromIterator<(HeaderName, T)> 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<'a, K, V> HttpTryFrom<&'a HashMap<K, V>> for HeaderMap<HeaderValue>
where
HeaderName: HttpTryFrom<&'a K>,
HeaderValue: HttpTryFrom<&'a V>
{
type Error = Error;

fn try_from(c: &'a HashMap<K, V>) -> Result<Self, Self::Error> {
c.into_iter()
.map(|(k, v)| -> ::Result<(HeaderName, HeaderValue)> {
let name : HeaderName = k.http_try_into()?;
let value : HeaderValue = v.http_try_into()?;
Ok((name, value))
})
.collect()
}
}

impl<T> Extend<(Option<HeaderName>, T)> for HeaderMap<T> {
/// Extend a `HeaderMap` with the contents of another `HeaderMap`.
///
Expand Down Expand Up @@ -3161,7 +3202,7 @@ mod as_header_name {
use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName};

/// A marker trait used to identify values that can be used as search keys
/// to a `HeaderMap`.
/// to a `HeaderMap`.
pub trait AsHeaderName: Sealed {}

// All methods are on this pub(super) trait, instead of `AsHeaderName`,
Expand Down
8 changes: 8 additions & 0 deletions src/header/name.rs
Expand Up @@ -1772,6 +1772,14 @@ impl<'a> HttpTryFrom<&'a str> for HeaderName {
}
}

impl<'a> HttpTryFrom<&'a String> for HeaderName {
type Error = InvalidHeaderName;
#[inline]
fn try_from(s: &'a String) -> Result<Self, Self::Error> {
Self::from_bytes(s.as_bytes())
}
}

impl<'a> HttpTryFrom<&'a [u8]> for HeaderName {
type Error = InvalidHeaderName;
#[inline]
Expand Down
8 changes: 8 additions & 0 deletions src/header/value.rs
Expand Up @@ -521,6 +521,14 @@ impl<'a> HttpTryFrom<&'a str> for HeaderValue {
}
}

impl<'a> HttpTryFrom<&'a String> for HeaderValue {
type Error = InvalidHeaderValue;
#[inline]
fn try_from(s: &'a String) -> Result<Self, Self::Error> {
Self::from_bytes(s.as_bytes())
}
}

impl<'a> HttpTryFrom<&'a [u8]> for HeaderValue {
type Error = InvalidHeaderValue;

Expand Down