use std::io;
use std::fmt::Display;
use futures::{Future, Poll};
use tokio_core::io::Io;
use tk_bufstream::{WriteBuf, WriteRaw, FutureWriteRaw};
use base_serializer::{MessageState, HeaderError};
use enums::{Version, Status};
use super::headers::Head;
pub struct Encoder<S: Io> {
state: MessageState,
io: WriteBuf<S>,
}
pub struct EncoderDone<S: Io> {
buf: WriteBuf<S>,
}
#[derive(Debug, Clone, Copy)]
pub struct ResponseConfig {
pub is_head: bool,
pub do_close: bool,
pub version: Version,
}
pub struct FutureRawBody<S>(FutureWriteRaw<S>);
pub struct RawBody<S> {
io: WriteRaw<S>,
}
impl<S: Io> Encoder<S> {
pub fn response_continue(&mut self) {
self.state.response_continue(&mut self.io.out_buf)
}
pub fn status(&mut self, status: Status) {
self.state.response_status(&mut self.io.out_buf,
status.code(), status.reason())
}
pub fn custom_status(&mut self, code: u16, reason: &str) {
self.state.response_status(&mut self.io.out_buf, code, reason)
}
pub fn add_header<V: AsRef<[u8]>>(&mut self, name: &str, value: V)
-> Result<(), HeaderError>
{
self.state.add_header(&mut self.io.out_buf, name, value.as_ref())
}
pub fn format_header<D: Display>(&mut self, name: &str, value: D)
-> Result<(), HeaderError>
{
self.state.format_header(&mut self.io.out_buf, name, value)
}
pub fn add_length(&mut self, n: u64)
-> Result<(), HeaderError>
{
self.state.add_length(&mut self.io.out_buf, n)
}
pub fn add_chunked(&mut self)
-> Result<(), HeaderError>
{
self.state.add_chunked(&mut self.io.out_buf)
}
pub fn is_started(&self) -> bool {
self.state.is_started()
}
pub fn done_headers(&mut self) -> Result<bool, HeaderError> {
self.state.done_headers(&mut self.io.out_buf)
}
pub fn write_body(&mut self, data: &[u8]) {
self.state.write_body(&mut self.io.out_buf, data)
}
pub fn is_complete(&self) -> bool {
self.state.is_complete()
}
pub fn done(mut self) -> EncoderDone<S> {
self.state.done(&mut self.io.out_buf);
EncoderDone { buf: self.io }
}
pub fn raw_body(self) -> FutureRawBody<S> {
assert!(self.state.is_after_headers());
FutureRawBody(self.io.borrow_raw())
}
}
impl<S: Io> RawBody<S> {
pub fn done(self) -> EncoderDone<S> {
EncoderDone { buf: self.io.into_buf() }
}
}
impl<S: Io> io::Write for Encoder<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.write_body(buf);
Ok((buf.len()))
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<S: Io> io::Write for RawBody<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.io.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.io.flush()
}
}
pub fn get_inner<S: Io>(e: EncoderDone<S>) -> WriteBuf<S> {
e.buf
}
pub fn new<S: Io>(io: WriteBuf<S>, cfg: ResponseConfig) -> Encoder<S> {
use base_serializer::Body::*;
Encoder {
state: MessageState::ResponseStart {
body: if cfg.is_head { Head } else { Normal },
version: cfg.version,
close: cfg.do_close || cfg.version == Version::Http10,
},
io: io,
}
}
impl ResponseConfig {
pub fn from(req: &Head) -> ResponseConfig {
ResponseConfig {
version: req.version(),
is_head: req.method() == "HEAD",
do_close: req.connection_close(),
}
}
}
impl<S: Io> Future for FutureRawBody<S> {
type Item = RawBody<S>;
type Error = io::Error;
fn poll(&mut self) -> Poll<RawBody<S>, io::Error> {
self.0.poll().map(|x| x.map(|y| RawBody { io: y }))
}
}
#[cfg(unix)]
mod sendfile {
use std::os::unix::io::{AsRawFd, RawFd};
use tokio_core::io::Io;
use super::RawBody;
impl<T: Io + AsRawFd> AsRawFd for RawBody<T> {
fn as_raw_fd(&self) -> RawFd {
self.io.as_raw_fd()
}
}
}