rusthyper

How can I implement a custom typed header for use with Hyper?


I'd prefer to take advantage of the type safety of Hyper's hyper::header::Headers#get method instead of using get_raw with a &str.

What is the best way to accomplish this?


Solution

  • Digging through the hyper::header::Headers source code, I found that there is a neat macro for generating the code: header!. You will need some incantation to make it useful, though:

    #[macro_use]
    extern crate hyper;
    
    use hyper::{Body, Method, Request, Response};
    use std::fmt::{self, Display};
    use std::str::FromStr;
    use std::num::ParseIntError;
    
    // For a header that looks like this:
    //    x-arbitrary-header-with-an-integer: 8
    
    #[derive(Clone, Debug, Eq, PartialEq)]
    pub struct ArbitraryNumber(i8);
    
    impl Display for ArbitraryNumber {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Arbitrary Protocol v{}", self.0)
        }
    }
    
    impl FromStr for ArbitraryNumber {
        type Err = ParseIntError;
    
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            s.parse::<i8>().map(|int| ArbitraryNumber(int))
        }
    }
    
    //impl Header for ArbitraryNumberHeader
    header! { (ArbitraryNumberHeader, "x-arbitrary-header-with-an-integer") => [ArbitraryNumber] }
    

    Once you've got a Response named res in scope, you can access this header like so:

    let arbitrary_header: AribitraryNumber = res.headers().get::<ArbitraryNumberHeader>().unwrap();