Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/headers/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,27 @@ pub trait Header {
}
}

impl<'a, 'b> Header for (&'a str, &'b str) {
impl Header for (&'static str, &'static str) {
fn header_name(&self) -> HeaderName {
HeaderName::from(self.0)
if self.0.chars().all(|c| c.is_ascii_lowercase()) {
HeaderName::from_lowercase_str(self.0)
} else {
HeaderName::from(self.0)
}
}

fn header_value(&self) -> HeaderValue {
HeaderValue::from_bytes(self.1.to_owned().into_bytes())
.expect("String slice should be valid ASCII")
HeaderValue::from_static_str(self.1)
}
}

impl Header for (String, String) {
fn header_name(&self) -> HeaderName {
self.0.parse().expect("Header name should be valid ASCII")
}

fn header_value(&self) -> HeaderValue {
self.1.parse().expect("Header value should be valid ASCII")
}
}

Expand Down
27 changes: 18 additions & 9 deletions src/headers/header_value.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::convert::TryFrom;
use std::fmt::{self, Debug, Display};
use std::str::FromStr;
Expand All @@ -11,7 +12,7 @@ use crate::Mime;
/// A header value.
#[derive(Clone, Eq, PartialEq, Hash)]
pub struct HeaderValue {
inner: String,
inner: Cow<'static, str>,
Copy link
Member

@jbr jbr Apr 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not pub struct HeaderValue<'a> { inner: Cow<'a, str> } and just use HeaderValue<'static> where we need it to be 'static?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jbr That'd make the API a little more awkward to use, and would potentially be a backwards-compatibility issue.

}

impl HeaderValue {
Expand All @@ -25,7 +26,7 @@ impl HeaderValue {

// This is permitted because ASCII is valid UTF-8, and we just checked that.
let string = unsafe { String::from_utf8_unchecked(bytes) };
Ok(Self { inner: string })
Ok(Self { inner: string.into() })
}

/// Converts a vector of bytes to a `HeaderValue` without checking that the string contains
Expand All @@ -39,19 +40,27 @@ impl HeaderValue {
/// that Strings are valid ASCII.
pub unsafe fn from_bytes_unchecked(bytes: Vec<u8>) -> Self {
let string = String::from_utf8_unchecked(bytes);
Self { inner: string }
Self { inner: string.into() }
}

/// Get the header value as a `&str`
pub fn as_str(&self) -> &str {
&self.inner
}

/// Create a new `HeaderValue` from a static-lifetime string slice.
pub(crate) fn from_static_str(value: &'static str) -> Self {
assert!(value.is_ascii(), "Bytes should be valid ASCII");
Self {
inner: Cow::Borrowed(value),
}
}
}

impl From<Mime> for HeaderValue {
fn from(mime: Mime) -> Self {
HeaderValue {
inner: format!("{}", mime),
inner: format!("{}", mime).into(),
}
}
}
Expand All @@ -60,15 +69,15 @@ impl From<Mime> for HeaderValue {
impl From<Cookie<'_>> for HeaderValue {
fn from(cookie: Cookie<'_>) -> Self {
HeaderValue {
inner: cookie.to_string(),
inner: cookie.to_string().into(),
}
}
}

impl From<&Mime> for HeaderValue {
fn from(mime: &Mime) -> Self {
HeaderValue {
inner: format!("{}", mime),
inner: format!("{}", mime).into(),
}
}
}
Expand All @@ -82,7 +91,7 @@ impl FromStr for HeaderValue {
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::ensure!(s.is_ascii(), "String slice should be valid ASCII");
Ok(Self {
inner: String::from(s),
inner: s.to_owned().into(),
})
}
}
Expand Down Expand Up @@ -113,7 +122,7 @@ impl PartialEq<str> for HeaderValue {
}
}

impl<'a> PartialEq<&'a str> for HeaderValue {
impl<'a, 'v> PartialEq<&'a str> for HeaderValue {
fn eq(&self, other: &&'a str) -> bool {
&self.inner == other
}
Expand All @@ -125,7 +134,7 @@ impl PartialEq<String> for HeaderValue {
}
}

impl<'a> PartialEq<&String> for HeaderValue {
impl<'a, 'v> PartialEq<&String> for HeaderValue {
fn eq(&self, other: &&String) -> bool {
&&self.inner == other
}
Expand Down