Skip to content

Commit 29fc199

Browse files
committed
Allow header access by indexing
This allows using the `[name]` syntax to get a header from a struct. This is implemented for Request, Response, Headers, and Trailers. IndexMut for assignment wasn't added because it can only be used to override existing values, which might be tricky.
1 parent 58ad74e commit 29fc199

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

src/headers/headers.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,29 @@
33
use std::collections::HashMap;
44
use std::convert::TryInto;
55
use std::iter::IntoIterator;
6+
use std::ops::Index;
7+
use std::str::FromStr;
68

79
use crate::headers::{
810
HeaderName, HeaderValues, IntoIter, Iter, IterMut, Names, ToHeaderValues, Values,
911
};
1012

1113
/// A collection of HTTP Headers.
14+
///
15+
/// Headers are never manually constructed, but are part of `Request`,
16+
/// `Response`, and `Trailers`. Each of these types implements `AsRef<Headers>`
17+
/// and `AsMut<Headers>` so functions that want to modify headers can be generic
18+
/// over either of these traits.
19+
///
20+
/// # Examples
21+
///
22+
/// ```
23+
/// use http_types::{Response, StatusCode};
24+
///
25+
/// let mut res = Response::new(StatusCode::Ok);
26+
/// res.insert_header("hello", "foo0").unwrap();
27+
/// assert_eq!(res["hello"], "foo0");
28+
/// ```
1229
#[derive(Debug, Clone)]
1330
pub struct Headers {
1431
pub(crate) headers: HashMap<HeaderName, HeaderValues>,
@@ -106,6 +123,35 @@ impl Headers {
106123
}
107124
}
108125

126+
impl Index<&HeaderName> for Headers {
127+
type Output = HeaderValues;
128+
129+
/// Returns a reference to the value corresponding to the supplied name.
130+
///
131+
/// # Panics
132+
///
133+
/// Panics if the name is not present in `Headers`.
134+
#[inline]
135+
fn index(&self, name: &HeaderName) -> &HeaderValues {
136+
self.get(name).expect("no entry found for name")
137+
}
138+
}
139+
140+
impl Index<&str> for Headers {
141+
type Output = HeaderValues;
142+
143+
/// Returns a reference to the value corresponding to the supplied name.
144+
///
145+
/// # Panics
146+
///
147+
/// Panics if the name is not present in `Headers`.
148+
#[inline]
149+
fn index(&self, name: &str) -> &HeaderValues {
150+
let name = HeaderName::from_str(name).expect("string slice needs to be valid ASCII");
151+
self.get(&name).expect("no entry found for name")
152+
}
153+
}
154+
109155
impl IntoIterator for Headers {
110156
type Item = (HeaderName, HeaderValues);
111157
type IntoIter = IntoIter;
@@ -173,4 +219,11 @@ mod tests {
173219

174220
Ok(())
175221
}
222+
223+
#[test]
224+
fn index_into_headers() {
225+
let mut headers = Headers::new();
226+
headers.insert("hello", "foo0").unwrap();
227+
assert_eq!(headers["hello"], "foo0");
228+
}
176229
}

src/request.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use async_std::sync;
33

44
use std::convert::TryInto;
55
use std::mem;
6+
use std::ops::Index;
67
use std::pin::Pin;
78
use std::task::{Context, Poll};
89

@@ -484,6 +485,34 @@ impl From<Request> for Body {
484485
}
485486
}
486487

488+
impl Index<&HeaderName> for Request {
489+
type Output = HeaderValues;
490+
491+
/// Returns a reference to the value corresponding to the supplied name.
492+
///
493+
/// # Panics
494+
///
495+
/// Panics if the name is not present in `Request`.
496+
#[inline]
497+
fn index(&self, name: &HeaderName) -> &HeaderValues {
498+
self.headers.index(name)
499+
}
500+
}
501+
502+
impl Index<&str> for Request {
503+
type Output = HeaderValues;
504+
505+
/// Returns a reference to the value corresponding to the supplied name.
506+
///
507+
/// # Panics
508+
///
509+
/// Panics if the name is not present in `Request`.
510+
#[inline]
511+
fn index(&self, name: &str) -> &HeaderValues {
512+
self.headers.index(name)
513+
}
514+
}
515+
487516
impl IntoIterator for Request {
488517
type Item = (HeaderName, HeaderValues);
489518
type IntoIter = headers::IntoIter;

src/response.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use async_std::sync;
33

44
use std::convert::TryInto;
55
use std::mem;
6+
use std::ops::Index;
67
use std::pin::Pin;
78
use std::task::{Context, Poll};
89

@@ -448,6 +449,33 @@ impl From<()> for Response {
448449
Response::new(StatusCode::NoContent)
449450
}
450451
}
452+
impl Index<&HeaderName> for Response {
453+
type Output = HeaderValues;
454+
455+
/// Returns a reference to the value corresponding to the supplied name.
456+
///
457+
/// # Panics
458+
///
459+
/// Panics if the name is not present in `Response`.
460+
#[inline]
461+
fn index(&self, name: &HeaderName) -> &HeaderValues {
462+
self.headers.index(name)
463+
}
464+
}
465+
466+
impl Index<&str> for Response {
467+
type Output = HeaderValues;
468+
469+
/// Returns a reference to the value corresponding to the supplied name.
470+
///
471+
/// # Panics
472+
///
473+
/// Panics if the name is not present in `Response`.
474+
#[inline]
475+
fn index(&self, name: &str) -> &HeaderValues {
476+
self.headers.index(name)
477+
}
478+
}
451479

452480
impl From<StatusCode> for Response {
453481
fn from(s: StatusCode) -> Self {

src/trailers.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use async_std::sync;
5555

5656
use std::convert::TryInto;
5757
use std::future::Future;
58-
use std::ops::{Deref, DerefMut};
58+
use std::ops::{Deref, DerefMut, Index};
5959
use std::pin::Pin;
6060
use std::task::{Context, Poll};
6161

@@ -181,6 +181,34 @@ impl DerefMut for Trailers {
181181
}
182182
}
183183

184+
impl Index<&HeaderName> for Trailers {
185+
type Output = HeaderValues;
186+
187+
/// Returns a reference to the value corresponding to the supplied name.
188+
///
189+
/// # Panics
190+
///
191+
/// Panics if the name is not present in `Trailers`.
192+
#[inline]
193+
fn index(&self, name: &HeaderName) -> &HeaderValues {
194+
self.headers.index(name)
195+
}
196+
}
197+
198+
impl Index<&str> for Trailers {
199+
type Output = HeaderValues;
200+
201+
/// Returns a reference to the value corresponding to the supplied name.
202+
///
203+
/// # Panics
204+
///
205+
/// Panics if the name is not present in `Trailers`.
206+
#[inline]
207+
fn index(&self, name: &str) -> &HeaderValues {
208+
self.headers.index(name)
209+
}
210+
}
211+
184212
/// The sending half of a channel to send trailers.
185213
///
186214
/// Unlike `async_std::sync::channel` the `send` method on this type can only be

0 commit comments

Comments
 (0)