Search code examples
rusthyper

Read gzip response with Hyper and Flate2


Hyper has the function fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> to read the contents of an HTTP response into the provided &mut [u8].

Flate2 can gunzip:

let mut d = GzDecoder::new("...".as_bytes()).unwrap();
let mut s = String::new();
d.read_to_string(&mut s).unwrap();
println!("{}", s);

I try to put the two things together:

fn gunzip(r: &Response) -> String {
    let mut zs: &mut [u8] = &mut[];
    r.read(zs);
    let mut d = GzDecoder::new(zs).unwrap();
    let mut s = String::new();
    d.read_to_string(&mut s).unwrap();
    s
}

And I get the error:

error[E0277]: the trait bound `[u8]: std::io::Read` is not satisfied
   --> tests/integration.rs:232:21
    |
232 |         let mut d = GzDecoder::new(zs).unwrap();
    |                     ^^^^^^^^^^^^^^ trait `[u8]: std::io::Read` not satisfied
    |
    = help: the following implementations were found:
    = help:   <&'a [u8] as std::io::Read>
    = note: required because of the requirements on the impl of `std::io::Read` for `&mut [u8]`
    = note: required by `<flate2::read::DecoderReader<R>>::new`

Where am I going wrong?


Edit: The final working solution:

fn gunzip(r: &mut Response) -> String {
    let mut buffer = Vec::new();
    let _ = r.read_to_end(&mut buffer).unwrap();
    let mut d = GzDecoder::new(buffer.as_slice()).unwrap();
    let mut s = String::new();
    d.read_to_string(&mut s).unwrap();
    s
}

Solution

  • The parameter to GzDecoder::new is defined with a generic type, so Rust will not perform some conversions that would happen if a fixed type was expected.

    You can convert a mutable slice into an immutable slice by dereferencing the mutable slice and then taking a reference to the result.

    let mut d = GzDecoder::new(&*zs).unwrap();