2

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
}
Synesso
  • 37,610
  • 35
  • 136
  • 207
  • (In response to a deleted comment...) Yes I did [try `&zs`]. Results in `trait '&&mut [u8]: std::io::Read' not satisfied`. – Synesso Oct 27 '16 at 22:11
  • Can you try adding a second & to it? (It sounds stupid, but it works on the [playground](https://play.rust-lang.org/?code=use%20std%3A%3Aio%3A%3ARead%3B%0A%0Afn%20foo(r%3A%20%26Read)%20%7B%0A%20%20%20%20%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20let%20mut%20a%20%3D%20%5B8u8%2C%206%2C%207%5D%3B%0A%20%20%20%20let%20mut%20bind%20%3D%20%26a%3B%0A%20%20%20%20%0A%20%20%20%20foo(%26%26bind%5B..%5D)%3B%0A%7D&version=stable&backtrace=0) ) – Neikos Oct 27 '16 at 22:16
  • `GzDecoder::new(&&zs).unwrap()` => `trait '&&&mut [u8]: std::io::Read' not satisfied`. – Synesso Oct 27 '16 at 22:21
  • That is interesting, because it does work in the playground. I'd also like to note `[]` is an array of length 0 and does not allow to grow. Which means that reading into it will read nothing in the end. Try your luck with `Vec` if you want to read all of it, for example through [`read_to_end`](https://doc.rust-lang.org/stable/std/io/trait.Read.html#method.read_to_end) – Neikos Oct 27 '16 at 22:27
  • This is for a hyper client, correct? – squiguy Oct 27 '16 at 22:43
  • Yes, hyper client. – Synesso Oct 27 '16 at 22:46
  • 1
    You should be able to mutably borrow `r` and pass that to the `GzDecoder` since it accepts types that implement `Read` which a client `Response` does. – squiguy Oct 27 '16 at 23:05

2 Answers2

2

Here is another way you can do it without using another buffer:

extern crate hyper;
extern crate flate2;

use std::io::Read;

use hyper::client::Client;
use hyper::header::{Headers, AcceptEncoding, Encoding, qitem};

use flate2::read::GzDecoder;

fn main() {
    let c = Client::new();

    let mut req = c.get("http://httpbin.org/gzip");
    let mut headers = Headers::new();
    headers.set(
        AcceptEncoding(vec![qitem(Encoding::Gzip)])
    );
    req = req.headers(headers);

    let res = req.send().unwrap();
    let mut decoder = GzDecoder::new(res).unwrap();
    let mut buf = String::new();

    let _ = decoder.read_to_string(&mut buf);
    println!("{}", buf);
}

This example uses the gzip endpoint from HTTPBIN for testing that the Response can be used in a GzDecoder.

Dependencies used in my Cargo file:

[dependencies]
hyper = "0.9"
flate2 = "0.2"

P.S. The unwrap() calls are for brevity's sake :)

squiguy
  • 32,370
  • 6
  • 56
  • 63
1

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();
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155