tower-web 0.3.7

Web framework with a focus on removing boilerplate
Documentation
extern crate tower_web;
extern crate bytes;
extern crate flate2;
extern crate futures;
extern crate rand;

use tower_web::util::buf_stream::BufStream;
use tower_web::util::buf_stream::deflate::CompressStream;

use bytes::Bytes;
use futures::{Poll, Future};
use flate2::Compression;
use flate2::read::DeflateDecoder;
use rand::{thread_rng, Rng};
use rand::distributions::{Distribution, Standard};

use std::cmp;
use std::io;
use std::io::prelude::*;

macro_rules! assert_round_trip {
    ($stream:expr, $expect:expr) => {{
        let data: Vec<u8> = $stream.collect().wait().unwrap();
        let mut decoder = DeflateDecoder::new(&data[..]);
        let mut actual = vec![];
        decoder.read_to_end(&mut actual).unwrap();
        assert_eq!(&actual[..], &$expect[..]);
    }}
}

#[test]
fn single_chunk() {
    let data: Vec<u8> = Standard.sample_iter(&mut thread_rng())
        .take(16 * 1024)
        .collect();

    let deflate = CompressStream::new(
        Mock::single_chunk(data.clone()),
        Compression::fast());

    assert_round_trip!(deflate, data);
}

#[test]
fn multi_chunk() {
    let data: Vec<u8> = Standard.sample_iter(&mut thread_rng())
        .take(16 * 1024)
        .collect();

    let deflate = CompressStream::new(
        Mock::rand_chunks(data.clone()),
        Compression::fast());

    assert_round_trip!(deflate, data);
}

struct Mock {
    chunks: Vec<Bytes>,
}

impl Mock {
    pub fn single_chunk(data: Vec<u8>) -> Mock {
        Mock { chunks: vec![data.into()] }
    }

    pub fn rand_chunks(data: Vec<u8>) -> Mock {
        let mut data = Bytes::from(data);
        let max = data.len() / 4;

        let mut rng = thread_rng();
        let mut chunks = vec![];

        while !data.is_empty() {
            let n = cmp::min(rng.gen_range(1, max), data.len());
            chunks.push(data.split_to(n));
        }

        Mock { chunks }
    }
}

impl BufStream for Mock {
    type Item = io::Cursor<Bytes>;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if self.chunks.is_empty() {
            return Ok(None.into());
        }

        let chunk = self.chunks.remove(0);
        let buf = io::Cursor::new(chunk);

        Ok(Some(buf).into())
    }
}