feat(lib): redesign API to use Futures and Tokio

There are many changes involved with this, but let's just talk about
user-facing changes.

- Creating a `Client` and `Server` now needs a Tokio `Core` event loop
to attach to.
- `Request` and `Response` both no longer implement the
`std::io::{Read,Write}` traits, but instead represent their bodies as a
`futures::Stream` of items, where each item is a `Chunk`.
- The `Client.request` method now takes a `Request`, instead of being
used as a builder, and returns a `Future` that resolves to `Response`.
- The `Handler` trait for servers is no more, and instead the Tokio
`Service` trait is used. This allows interoperability with generic
middleware.

BREAKING CHANGE: A big sweeping set of breaking changes.
This commit is contained in:
Sean McArthur
2016-11-17 17:31:42 -08:00
parent e23689122a
commit 2d2d5574a6
43 changed files with 2775 additions and 5033 deletions

View File

@@ -1,6 +1,9 @@
use std::cmp;
use std::io::{self, Read, Write};
use futures::Async;
use tokio::io::Io;
#[derive(Debug)]
pub struct Buf {
vec: Vec<u8>
@@ -8,8 +11,12 @@ pub struct Buf {
impl Buf {
pub fn new() -> Buf {
Buf::wrap(vec![])
}
pub fn wrap(vec: Vec<u8>) -> Buf {
Buf {
vec: vec![]
vec: vec,
}
}
}
@@ -58,27 +65,41 @@ impl ::vecio::Writev for Buf {
}
#[derive(Debug)]
pub struct Async<T> {
pub struct AsyncIo<T> {
inner: T,
bytes_until_block: usize,
error: Option<io::Error>,
}
impl<T> Async<T> {
pub fn new(inner: T, bytes: usize) -> Async<T> {
Async {
impl<T> AsyncIo<T> {
pub fn new(inner: T, bytes: usize) -> AsyncIo<T> {
AsyncIo {
inner: inner,
bytes_until_block: bytes
bytes_until_block: bytes,
error: None,
}
}
pub fn block_in(&mut self, bytes: usize) {
self.bytes_until_block = bytes;
}
pub fn error(&mut self, err: io::Error) {
self.error = Some(err);
}
}
impl<T: Read> Read for Async<T> {
impl AsyncIo<Buf> {
pub fn new_buf<T: Into<Vec<u8>>>(buf: T, bytes: usize) -> AsyncIo<Buf> {
AsyncIo::new(Buf::wrap(buf.into()), bytes)
}
}
impl<T: Read> Read for AsyncIo<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if self.bytes_until_block == 0 {
if let Some(err) = self.error.take() {
Err(err)
} else if self.bytes_until_block == 0 {
Err(io::Error::new(io::ErrorKind::WouldBlock, "mock block"))
} else {
let n = cmp::min(self.bytes_until_block, buf.len());
@@ -89,9 +110,11 @@ impl<T: Read> Read for Async<T> {
}
}
impl<T: Write> Write for Async<T> {
impl<T: Write> Write for AsyncIo<T> {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
if self.bytes_until_block == 0 {
if let Some(err) = self.error.take() {
Err(err)
} else if self.bytes_until_block == 0 {
Err(io::Error::new(io::ErrorKind::WouldBlock, "mock block"))
} else {
let n = cmp::min(self.bytes_until_block, data.len());
@@ -106,7 +129,25 @@ impl<T: Write> Write for Async<T> {
}
}
impl<T: Write> ::vecio::Writev for Async<T> {
impl<T: Read + Write> Io for AsyncIo<T> {
fn poll_read(&mut self) -> Async<()> {
if self.bytes_until_block == 0 {
Async::NotReady
} else {
Async::Ready(())
}
}
fn poll_write(&mut self) -> Async<()> {
if self.bytes_until_block == 0 {
Async::NotReady
} else {
Async::Ready(())
}
}
}
impl<T: Write> ::vecio::Writev for AsyncIo<T> {
fn writev(&mut self, bufs: &[&[u8]]) -> io::Result<usize> {
let cap = bufs.iter().map(|buf| buf.len()).fold(0, |total, next| total + next);
let mut vec = Vec::with_capacity(cap);
@@ -118,7 +159,7 @@ impl<T: Write> ::vecio::Writev for Async<T> {
}
}
impl ::std::ops::Deref for Async<Buf> {
impl ::std::ops::Deref for AsyncIo<Buf> {
type Target = [u8];
fn deref(&self) -> &[u8] {