<commit_before>use nix::sys::epoll::*;
use std::default::Default;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::slice;
use super::{Available, HUP, NONE, READ, WRITE};

pub type Token = u64;

pub struct PollHandle {
    epoll_fd: RawFd,
}

impl PollHandle {
    pub fn schedule_read<Fd: AsRawFd>(&self, file: &Fd, token: Token) {
        self.schedule_read_rawfd(file.as_raw_fd(), token);
    }

    pub fn schedule_read_rawfd(&self, fd: RawFd, token: Token) {
        let mut kind = EpollEventKind::empty();
        kind.insert(EPOLLIN); // Want to receive input
        kind.insert(EPOLLET); // Edge triggered.
        kind.insert(EPOLLONESHOT); // One shot
        let event = EpollEvent {
            events: kind,
            data: token,
        };
        epoll_ctl(self.epoll_fd, EpollOp::EpollCtlMod, fd, &event).unwrap();
    }

    pub fn schedule_write<Fd: AsRawFd>(&self, file: &Fd, token: Token) {
        self.schedule_write_rawfd(file.as_raw_fd(), token);
    }

    pub fn schedule_write_rawfd(&self, fd: RawFd, token: Token) {
        let mut kind = EpollEventKind::empty();
        kind.insert(EPOLLOUT); // Want to receive input
        kind.insert(EPOLLET); // Edge triggered.
        kind.insert(EPOLLONESHOT); // One shot
        let event = EpollEvent {
            events: kind,
            data: token,
        };
        epoll_ctl(self.epoll_fd, EpollOp::EpollCtlMod, fd, &event).unwrap();
    }

    /// This assumes file is already set to be non-blocking. This must also be called only the first time round.
    pub fn new_io_port<Fd: AsRawFd>(&self, file: &Fd, token: Token) {
        self.new_io_fd(file.as_raw_fd(), token);
    }

    pub fn new_io_fd(&self, fd: RawFd, token: Token) {
        let mut kind = EpollEventKind::empty();
        kind.insert(EPOLLET); // Edge triggered.
        kind.insert(EPOLLONESHOT); // One shot
        let event = EpollEvent {
            events: kind,
            data: token,
        };
        epoll_ctl(self.epoll_fd, EpollOp::EpollCtlAdd, fd, &event).unwrap();
    }
}

pub struct PollScheduler {
    epoll_fd: RawFd,
    ready_tokens: Vec<EpollEvent>,
    events: usize,
}

impl Default for PollScheduler {
    fn default() -> PollScheduler {
        PollScheduler::new()
    }
}

impl PollScheduler {
    pub fn new_poll_handle(&self) -> PollHandle {
        PollHandle { epoll_fd: self.epoll_fd }
    }

    pub fn new() -> PollScheduler {
        PollScheduler {
            epoll_fd: epoll_create().unwrap(),
            ready_tokens: Vec::with_capacity(32),
            events: 0,
        }
    }

    #[inline]
    fn epoll_kind_to_available(&self, kind: &EpollEventKind) -> Available {
        let mut available = NONE;
        if kind.contains(EPOLLIN) {
            available |= READ
        };
        if kind.contains(EPOLLOUT) {
            available |= WRITE
        };
        if kind.contains(EPOLLHUP) || kind.contains(EPOLLERR) {
            available |= HUP
        };
        available
    }

    pub fn get_token_noblock(&mut self) -> Option<(Token, Available)> {
        if self.events > 0 {
                self.events -= 1;
                self.ready_tokens.pop()
            } else {
                let dest =
                    unsafe { slice::from_raw_parts_mut(self.ready_tokens.as_mut_ptr(), self.ready_tokens.capacity()) };
                self.events = epoll_wait(self.epoll_fd, dest, 0).unwrap();
                unsafe { self.ready_tokens.set_len(self.events) };
                self.ready_tokens.pop()
            }
            .map(|t| (t.data, self.epoll_kind_to_available(&t.events)))
    }
}
<commit_msg>Fix nix epoll code<commit_after>use nix::sys::epoll::*;
use std::default::Default;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::slice;
use super::{Available, HUP, NONE, READ, WRITE};

pub type Token = u64;

pub struct PollHandle {
    epoll_fd: RawFd,
}

impl PollHandle {
    pub fn schedule_read<Fd: AsRawFd>(&self, file: &Fd, token: Token) {
        self.schedule_read_rawfd(file.as_raw_fd(), token);
    }

    pub fn schedule_read_rawfd(&self, fd: RawFd, token: Token) {
        let mut event = EpollEvent::new(EPOLLIN | EPOLLET | EPOLLONESHOT, token);
        epoll_ctl(self.epoll_fd, EpollOp::EpollCtlMod, fd, &mut event).unwrap();
    }

    pub fn schedule_write<Fd: AsRawFd>(&self, file: &Fd, token: Token) {
        self.schedule_write_rawfd(file.as_raw_fd(), token);
    }

    pub fn schedule_write_rawfd(&self, fd: RawFd, token: Token) {
        let mut event = EpollEvent::new(EPOLLOUT | EPOLLET | EPOLLONESHOT, token);
        epoll_ctl(self.epoll_fd, EpollOp::EpollCtlMod, fd, &mut event).unwrap();
    }

    /// This assumes file is already set to be non-blocking. This must also be called only the first time round.
    pub fn new_io_port<Fd: AsRawFd>(&self, file: &Fd, token: Token) {
        self.new_io_fd(file.as_raw_fd(), token);
    }

    pub fn new_io_fd(&self, fd: RawFd, token: Token) {
        let mut event = EpollEvent::new(EPOLLET | EPOLLONESHOT, token);
        epoll_ctl(self.epoll_fd, EpollOp::EpollCtlAdd, fd, &mut event).unwrap();
    }
}

pub struct PollScheduler {
    epoll_fd: RawFd,
    ready_tokens: Vec<EpollEvent>,
    events: usize,
}

impl Default for PollScheduler {
    fn default() -> PollScheduler {
        PollScheduler::new()
    }
}

impl PollScheduler {
    pub fn new_poll_handle(&self) -> PollHandle {
        PollHandle { epoll_fd: self.epoll_fd }
    }

    pub fn new() -> PollScheduler {
        PollScheduler {
            epoll_fd: epoll_create().unwrap(),
            ready_tokens: Vec::with_capacity(32),
            events: 0,
        }
    }

    #[inline]
    fn epoll_kind_to_available(&self, kind: &EpollFlags) -> Available {
        let mut available = NONE;
        if kind.contains(EPOLLIN) {
            available |= READ
        };
        if kind.contains(EPOLLOUT) {
            available |= WRITE
        };
        if kind.contains(EPOLLHUP) || kind.contains(EPOLLERR) {
            available |= HUP
        };
        available
    }

    pub fn get_token_noblock(&mut self) -> Option<(Token, Available)> {
        if self.events > 0 {
                self.events -= 1;
                self.ready_tokens.pop()
            } else {
                let dest =
                    unsafe { slice::from_raw_parts_mut(self.ready_tokens.as_mut_ptr(), self.ready_tokens.capacity()) };
                self.events = epoll_wait(self.epoll_fd, dest, 0).unwrap();
                unsafe { self.ready_tokens.set_len(self.events) };
                self.ready_tokens.pop()
            }
            .map(|t| (t.data(), self.epoll_kind_to_available(&t.events())))
    }
}
<|endoftext|>


<commit_before>//! Iron's HTTP Request representation and associated methods.
use std::fmt::{self, Debug};
use std::net::SocketAddr;

use futures::Stream;

use http;
use http::version::Version as HttpVersion;

use method::Method;
use plugin::Extensible;
use typemap::{Key, TypeMap};

pub use hyper::Body;
pub use hyper::Request as HttpRequest;

#[cfg(test)]
use std::net::ToSocketAddrs;

pub use self::url::Url;

use error::HttpError;
use headers::{self, HeaderMap};
use {Plugin, Protocol, Set};

mod url;

/// The `Request` given to all `Middleware`.
///
/// Stores all the properties of the client's request plus
/// an `TypeMap` for data communication between middleware.
pub struct Request {
    /// The requested URL.
    pub url: Url,

    /// The local address of the request.
    pub local_addr: Option<SocketAddr>,

    /// The request headers.
    pub headers: HeaderMap,

    /// The request body as a reader.
    pub body: Option<Body>,

    /// The request method.
    pub method: Method,

    /// Extensible storage for data passed between middleware.
    pub extensions: TypeMap,

    /// The version of the HTTP protocol used.
    pub version: HttpVersion,

    _p: (),
}

impl Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "Request {{"));

        try!(writeln!(f, "    url: {:?}", self.url));
        try!(writeln!(f, "    method: {:?}", self.method));
        try!(writeln!(f, "    local_addr: {:?}", self.local_addr));

        try!(write!(f, "}}"));
        Ok(())
    }
}

impl Request {
    /// Create a request from an HttpRequest.
    ///
    /// This constructor consumes the HttpRequest.
    pub fn from_http(
        req: HttpRequest<Body>,
        local_addr: Option<SocketAddr>,
        protocol: &Protocol,
    ) -> Result<Request, String> {
        let (
            http::request::Parts {
                method,
                uri,
                version,
                headers,
                ..
            },
            body,
        ) = req.into_parts();

        let url = {
            let path = uri.path();

            let mut socket_ip = String::new();
            let (host, port) = if let Some(host) = uri.host() {
                (host, uri.port())
            } else if let Some(host) = headers.get(headers::HOST).and_then(|h| h.to_str().ok()) {
                let mut parts = host.split(':');
                let hostname = parts.next().unwrap();
                let port = parts.next().and_then(|p| p.parse::<u16>().ok());
                (hostname, port)
            } else if version < HttpVersion::HTTP_11 {
                if let Some(local_addr) = local_addr {
                    match local_addr {
                        SocketAddr::V4(addr4) => socket_ip.push_str(&format!("{}", addr4.ip())),
                        SocketAddr::V6(addr6) => socket_ip.push_str(&format!("[{}]", addr6.ip())),
                    }
                    (socket_ip.as_ref(), Some(local_addr.port()))
                } else {
                    return Err("No fallback host specified".into());
                }
            } else {
                return Err("No host specified in request".into());
            };

            let url_string = if let Some(port) = port {
                format!("{}://{}:{}{}", protocol.name(), host, port, path)
            } else {
                format!("{}://{}{}", protocol.name(), host, path)
            };

            match Url::parse(&url_string) {
                Ok(url) => url,
                Err(e) => return Err(format!("Couldn't parse requested URL: {}", e)),
            }
        };

        Ok(Request {
            url,
            local_addr,
            headers,
            body: Some(body),
            method,
            extensions: TypeMap::new(),
            version,
            _p: (),
        })
    }

    /// Get the contents of the body as a Vec<u8>
    ///
    /// This consumes the body future and turns it into Vec<u8>.  Note this should not be called
    /// from the main hyper thread, as it will potentially deadlock.
    pub fn get_body_contents(&mut self) -> Result<&Vec<u8>, HttpError> {
        if let Some(reader) = self.body.take() {
            let body = reader.wait().fold(Ok(Vec::new()), |r, input| {
                if let Ok(mut v) = r {
                    input.map(move |next_body_chunk| {
                        v.extend_from_slice(&next_body_chunk);
                        v
                    })
                } else {
                    r
                }
            });
            match body {
                Ok(body) => self.extensions.insert::<RequestBodyKey>(body),
                Err(e) => return Err(e),
            };
        }
        Ok(self.extensions.get::<RequestBodyKey>().unwrap())
    }

    #[cfg(test)]
    pub fn stub() -> Request {
        Request {
            url: Url::parse("http://www.rust-lang.org").unwrap(),
            local_addr: "localhost:3000".to_socket_addrs().unwrap().next(),
            headers: HeaderMap::new(),
            body: Some(Body::empty()),
            method: Method::GET,
            extensions: TypeMap::new(),
            version: HttpVersion::HTTP_11,
            _p: (),
        }
    }
}

struct RequestBodyKey;

impl Key for RequestBodyKey {
    type Value = Vec<u8>;
}

// Allow plugins to attach to requests.
impl Extensible for Request {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Plugin for Request {}
impl Set for Request {}

#[cfg(test)]
mod test {
    use super::*;

    use headers;

    use url_ext::Host::*;

    #[test]
    fn test_request_parse_absolute_uri() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "http://my-host/path".parse().unwrap();

        let iron_request = Request::from_http(hyper_request, None, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host"));
    }

    #[test]
    fn test_request_parse_host_header_only() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "/path".parse().unwrap();
        hyper_request
            .headers_mut()
            .insert(headers::HOST, "my-host".parse().unwrap());

        let iron_request = Request::from_http(hyper_request, None, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host"));
    }

    #[test]
    fn test_request_parse_host_header_and_absolute_uri() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "http://my-host-uri/path".parse().unwrap();
        hyper_request
            .headers_mut()
            .insert(headers::HOST, "my-host-header".parse().unwrap());

        let iron_request = Request::from_http(hyper_request, None, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host-uri"));
    }

    #[test]
    fn test_request_parse_ipv4_socket_only() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "/path".parse().unwrap();
        *hyper_request.version_mut() = HttpVersion::HTTP_10;

        let socket_addr = Some("1.2.3.4:80".parse().unwrap());
        let iron_request = Request::from_http(hyper_request, socket_addr, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Ipv4([1, 2, 3, 4].into()));
    }

    #[test]
    fn test_request_parse_ipv6_socket_only() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "/path".parse().unwrap();
        *hyper_request.version_mut() = HttpVersion::HTTP_10;

        let socket_addr = Some("[1:2:3:4:5:6:7:8]:80".parse().unwrap());
        let iron_request = Request::from_http(hyper_request, socket_addr, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(
            iron_request.url.host(),
            Ipv6([1, 2, 3, 4, 5, 6, 7, 8].into())
        );
    }

    #[test]
    fn test_request_parse_host_header_ipv4_socket_and_absolute_uri() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "http://my-host-uri/path".parse().unwrap();
        hyper_request
            .headers_mut()
            .insert(headers::HOST, "my-host-header".parse().unwrap());

        let socket_addr = Some("1.2.3.4:80".parse().unwrap());
        let iron_request = Request::from_http(hyper_request, socket_addr, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host-uri"));
    }
}
<commit_msg>(fix) Use port_part() insead of deprecated port()<commit_after>//! Iron's HTTP Request representation and associated methods.
use std::fmt::{self, Debug};
use std::net::SocketAddr;

use futures::Stream;

use http;
use http::version::Version as HttpVersion;

use method::Method;
use plugin::Extensible;
use typemap::{Key, TypeMap};

pub use hyper::Body;
pub use hyper::Request as HttpRequest;

#[cfg(test)]
use std::net::ToSocketAddrs;

pub use self::url::Url;

use error::HttpError;
use headers::{self, HeaderMap};
use {Plugin, Protocol, Set};

mod url;

/// The `Request` given to all `Middleware`.
///
/// Stores all the properties of the client's request plus
/// an `TypeMap` for data communication between middleware.
pub struct Request {
    /// The requested URL.
    pub url: Url,

    /// The local address of the request.
    pub local_addr: Option<SocketAddr>,

    /// The request headers.
    pub headers: HeaderMap,

    /// The request body as a reader.
    pub body: Option<Body>,

    /// The request method.
    pub method: Method,

    /// Extensible storage for data passed between middleware.
    pub extensions: TypeMap,

    /// The version of the HTTP protocol used.
    pub version: HttpVersion,

    _p: (),
}

impl Debug for Request {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(f, "Request {{"));

        try!(writeln!(f, "    url: {:?}", self.url));
        try!(writeln!(f, "    method: {:?}", self.method));
        try!(writeln!(f, "    local_addr: {:?}", self.local_addr));

        try!(write!(f, "}}"));
        Ok(())
    }
}

impl Request {
    /// Create a request from an HttpRequest.
    ///
    /// This constructor consumes the HttpRequest.
    pub fn from_http(
        req: HttpRequest<Body>,
        local_addr: Option<SocketAddr>,
        protocol: &Protocol,
    ) -> Result<Request, String> {
        let (
            http::request::Parts {
                method,
                uri,
                version,
                headers,
                ..
            },
            body,
        ) = req.into_parts();

        let url = {
            let path = uri.path();

            let mut socket_ip = String::new();
            let (host, port) = if let Some(host) = uri.host() {
                (host, uri.port_part().map(|p| p.as_u16()))
            } else if let Some(host) = headers.get(headers::HOST).and_then(|h| h.to_str().ok()) {
                let mut parts = host.split(':');
                let hostname = parts.next().unwrap();
                let port = parts.next().and_then(|p| p.parse::<u16>().ok());
                (hostname, port)
            } else if version < HttpVersion::HTTP_11 {
                if let Some(local_addr) = local_addr {
                    match local_addr {
                        SocketAddr::V4(addr4) => socket_ip.push_str(&format!("{}", addr4.ip())),
                        SocketAddr::V6(addr6) => socket_ip.push_str(&format!("[{}]", addr6.ip())),
                    }
                    (socket_ip.as_ref(), Some(local_addr.port()))
                } else {
                    return Err("No fallback host specified".into());
                }
            } else {
                return Err("No host specified in request".into());
            };

            let url_string = if let Some(port) = port {
                format!("{}://{}:{}{}", protocol.name(), host, port, path)
            } else {
                format!("{}://{}{}", protocol.name(), host, path)
            };

            match Url::parse(&url_string) {
                Ok(url) => url,
                Err(e) => return Err(format!("Couldn't parse requested URL: {}", e)),
            }
        };

        Ok(Request {
            url,
            local_addr,
            headers,
            body: Some(body),
            method,
            extensions: TypeMap::new(),
            version,
            _p: (),
        })
    }

    /// Get the contents of the body as a Vec<u8>
    ///
    /// This consumes the body future and turns it into Vec<u8>.  Note this should not be called
    /// from the main hyper thread, as it will potentially deadlock.
    pub fn get_body_contents(&mut self) -> Result<&Vec<u8>, HttpError> {
        if let Some(reader) = self.body.take() {
            let body = reader.wait().fold(Ok(Vec::new()), |r, input| {
                if let Ok(mut v) = r {
                    input.map(move |next_body_chunk| {
                        v.extend_from_slice(&next_body_chunk);
                        v
                    })
                } else {
                    r
                }
            });
            match body {
                Ok(body) => self.extensions.insert::<RequestBodyKey>(body),
                Err(e) => return Err(e),
            };
        }
        Ok(self.extensions.get::<RequestBodyKey>().unwrap())
    }

    #[cfg(test)]
    pub fn stub() -> Request {
        Request {
            url: Url::parse("http://www.rust-lang.org").unwrap(),
            local_addr: "localhost:3000".to_socket_addrs().unwrap().next(),
            headers: HeaderMap::new(),
            body: Some(Body::empty()),
            method: Method::GET,
            extensions: TypeMap::new(),
            version: HttpVersion::HTTP_11,
            _p: (),
        }
    }
}

struct RequestBodyKey;

impl Key for RequestBodyKey {
    type Value = Vec<u8>;
}

// Allow plugins to attach to requests.
impl Extensible for Request {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Plugin for Request {}
impl Set for Request {}

#[cfg(test)]
mod test {
    use super::*;

    use headers;

    use url_ext::Host::*;

    #[test]
    fn test_request_parse_absolute_uri() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "http://my-host/path".parse().unwrap();

        let iron_request = Request::from_http(hyper_request, None, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host"));
    }

    #[test]
    fn test_request_parse_host_header_only() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "/path".parse().unwrap();
        hyper_request
            .headers_mut()
            .insert(headers::HOST, "my-host".parse().unwrap());

        let iron_request = Request::from_http(hyper_request, None, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host"));
    }

    #[test]
    fn test_request_parse_host_header_and_absolute_uri() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "http://my-host-uri/path".parse().unwrap();
        hyper_request
            .headers_mut()
            .insert(headers::HOST, "my-host-header".parse().unwrap());

        let iron_request = Request::from_http(hyper_request, None, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host-uri"));
    }

    #[test]
    fn test_request_parse_ipv4_socket_only() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "/path".parse().unwrap();
        *hyper_request.version_mut() = HttpVersion::HTTP_10;

        let socket_addr = Some("1.2.3.4:80".parse().unwrap());
        let iron_request = Request::from_http(hyper_request, socket_addr, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Ipv4([1, 2, 3, 4].into()));
    }

    #[test]
    fn test_request_parse_ipv6_socket_only() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "/path".parse().unwrap();
        *hyper_request.version_mut() = HttpVersion::HTTP_10;

        let socket_addr = Some("[1:2:3:4:5:6:7:8]:80".parse().unwrap());
        let iron_request = Request::from_http(hyper_request, socket_addr, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(
            iron_request.url.host(),
            Ipv6([1, 2, 3, 4, 5, 6, 7, 8].into())
        );
    }

    #[test]
    fn test_request_parse_host_header_ipv4_socket_and_absolute_uri() {
        let mut hyper_request = HttpRequest::new(Body::empty());
        *hyper_request.method_mut() = Method::GET;
        *hyper_request.uri_mut() = "http://my-host-uri/path".parse().unwrap();
        hyper_request
            .headers_mut()
            .insert(headers::HOST, "my-host-header".parse().unwrap());

        let socket_addr = Some("1.2.3.4:80".parse().unwrap());
        let iron_request = Request::from_http(hyper_request, socket_addr, &Protocol::http())
            .expect("A valid Iron request");

        assert_eq!(iron_request.url.host(), Domain("my-host-uri"));
    }
}
<|endoftext|>


<commit_before>use std::marker;
use std::cmp;
use std::collections::HashMap;
use std::iter::FromIterator;

use solicit::http::client::RequestStream;
use solicit::http::client::ClientSession;
use solicit::http::session::Client;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataError;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::Stream as solicit_Stream;
use solicit::http::session::StreamIter;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::SendStatus;
use solicit::http::connection::EndStream;
use solicit::http::connection::DataChunk;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::frame::RawFrame;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::TaskIo;
use tokio_core::io::TaskIoRead;
use tokio_core::io::TaskIoWrite;
use tokio_core::LoopHandle;

use error::*;
use futures_misc::*;

use solicit_async::*;
use solicit_misc::*;

trait ResponseHandler : Send + 'static {
    fn headers(self) -> HttpFuture<Self>;
    fn body_chunk(self) -> HttpFuture<Self>;
    fn end(self) -> HttpFuture<()>;
}

struct GrpcHttp2ClientStream2<H : ResponseHandler> {
    state: StreamState,
    response_handler: H,
}

impl<H : ResponseHandler> solicit_Stream for GrpcHttp2ClientStream2<H> {
    fn new_data_chunk(&mut self, data: &[u8]) {
    }

    fn set_headers<'n, 'v>(&mut self, headers: Vec<Header<'n, 'v>>) {
    }

    fn set_state(&mut self, state: StreamState) {
        self.state = state;
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        unimplemented!()
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

struct MySessionState<H : ResponseHandler> {
    streams: HashMap<StreamId, GrpcHttp2ClientStream2<H>>,
    next_stream_id: StreamId,
}

impl<H : ResponseHandler> MySessionState<H> {
    fn remove_closed_streams(&mut self) {
        let ids: Vec<StreamId> = self.streams
            .iter()
            .filter_map(|(id, s)| {
                if s.is_closed() {
                    Some(*id)
                } else {
                    None
                }
            })
            .collect();
        Vec::from_iter(ids.into_iter().map(|i| self.remove_stream(i).unwrap()));
    }
}

impl<H : ResponseHandler> SessionState for MySessionState<H> {
    type Stream = GrpcHttp2ClientStream2<H>;

    fn insert_outgoing(&mut self, stream: Self::Stream) -> StreamId {
        let id = self.next_stream_id;
        self.streams.insert(id, stream);
        self.next_stream_id += 2;
        id
    }

    fn insert_incoming(&mut self, stream_id: StreamId, stream: Self::Stream) -> Result<(), ()> {
        // TODO: assert parity
        // TODO: Assert that the stream IDs are monotonically increasing!
        self.streams.insert(stream_id, stream);
        Ok(())
    }

    #[inline]
    fn get_stream_ref(&self, stream_id: StreamId) -> Option<&Self::Stream> {
        self.streams.get(&stream_id)
    }

    #[inline]
    fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut Self::Stream> {
        self.streams.get_mut(&stream_id)
    }

    #[inline]
    fn remove_stream(&mut self, stream_id: StreamId) -> Option<Self::Stream> {
        self.streams.remove(&stream_id)
    }

    #[inline]
    fn iter(&mut self) -> StreamIter<GrpcHttp2ClientStream2<H>> {
        // https://github.com/mlalic/solicit/pull/34
        unimplemented!()
    }

    /// Number of currently active streams
    #[inline]
    fn len(&self) -> usize {
        self.streams.len()
    }
}

struct Inner<H : ResponseHandler> {
    host: String,
    conn: HttpConnection,
    call_tx: tokio_core::Sender<ToWriteMessage<H>>,
    session_state: MySessionState<H>,
}

struct HttpConnectionAsync<H : ResponseHandler> {
    inner: TaskRcMut<Inner<H>>,
}

struct StartRequestMessage<H : ResponseHandler> {
    headers: Vec<StaticHeader>,
    body: HttpStream<Vec<u8>>,
    response_handler: H,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

struct ReadToWriteMessage {
    buf: Vec<u8>,
}

enum ToWriteMessage<H : ResponseHandler> {
    Start(StartRequestMessage<H>),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    FromRead(ReadToWriteMessage),
}

struct WriteLoop<H : ResponseHandler> {
    write: TaskIoWrite<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> WriteLoop<H> {
    fn write_all(self, buf: Vec<u8>) -> HttpFuture<Self> {
        let WriteLoop { write, inner } = self;

        tokio_io::write_all(write, buf)
            .map(move |(write, _)| WriteLoop { write: write, inner: inner })
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_from_read(self, message: ReadToWriteMessage) -> HttpFuture<Self> {
        self.write_all(message.buf)
    }

    fn process_start(self, start: StartRequestMessage<H>) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;
        let (buf, stream_id) = self.inner.with(move |inner: &mut Inner<H>| {

            let stream = GrpcHttp2ClientStream2 {
                state: StreamState::Open,
                response_handler: response_handler,
            };
            let stream_id = inner.session_state.insert_outgoing(stream);

            let send_buf = {
                let mut send_buf = VecSendFrame(Vec::new());

                inner.conn.sender(&mut send_buf).send_headers(headers, stream_id, EndStream::No).unwrap();

                (send_buf.0, stream_id)
            };

            send_buf
        });

        self.write_all(buf)
            .and_then(move |wl: WriteLoop<H>| {
                body.fold(wl, move |wl: WriteLoop<H>, chunk| {
                    wl.inner.with(|inner: &mut Inner<H>| {
                        inner.call_tx.send(ToWriteMessage::BodyChunk(BodyChunkMessage {
                            stream_id: stream_id,
                            chunk: chunk,
                        }))
                    });
                    futures::finished::<_, HttpError>(wl)
                })
            })
            .and_then(move |wl: WriteLoop<H>| {
                wl.inner.with(|inner: &mut Inner<H>| {
                    inner.call_tx.send(ToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    }));
                });
                futures::finished::<_, HttpError>(wl)
            })
            .boxed()
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            {
                let stream = inner.session_state.get_stream_mut(stream_id);
                // TODO: check stream state
            }

            let mut send_buf = VecSendFrame(Vec::new());

            let mut pos = 0;
            const MAX_CHUNK_SIZE: usize = 8 * 1024;
            while pos < chunk.len() {
                let end = cmp::min(chunk.len(), pos + MAX_CHUNK_SIZE);

                let data_chunk = DataChunk::new_borrowed(&chunk[pos..end], stream_id, EndStream::No);

                inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

                pos = end;
            }

            send_buf.0
        });

        self.write_all(buf)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            let mut send_buf = VecSendFrame(Vec::new());

            let chunk = Vec::new();
            let data_chunk = DataChunk::new_borrowed(&chunk[..], stream_id, EndStream::Yes);

            inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

            send_buf.0
        });

        futures::finished(self).boxed()
    }

    fn process_message(self, message: ToWriteMessage<H>) -> HttpFuture<Self> {
        match message {
            ToWriteMessage::Start(start) => self.process_start(start),
            ToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ToWriteMessage::End(end) => self.process_end(end),
            ToWriteMessage::FromRead(from_read) => self.process_from_read(from_read),
        }
    }

    fn run(self, requests: tokio_core::Receiver<ToWriteMessage<H>>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        requests
            .fold(self, move |wl, message: ToWriteMessage<H>| {
                wl.process_message(message)
            })
            .map(|_| ())
            .boxed()
    }
}

struct ReadLoop<H : ResponseHandler> {
    read: TaskIoRead<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> ReadLoop<H> {
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let ReadLoop { read, inner } = self;
        recv_raw_frame(read)
            .map(|(read, frame)| (ReadLoop { read: read, inner: inner}, frame))
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_raw_frame(self, raw_frame: RawFrame) -> HttpFuture<Self> {

        self.inner.with(|inner: &mut Inner<H>| {
            let mut send = VecSendFrame(Vec::new());
            {
                let mut session = ClientSession::new(&mut inner.session_state, &mut send);
                inner.conn.handle_next_frame(&mut OnceReceiveFrame::new(raw_frame), &mut session)
                    .unwrap();
            }

            inner.session_state.remove_closed_streams();

            if !send.0.is_empty() {
                inner.call_tx.send(ToWriteMessage::FromRead(ReadToWriteMessage { buf: send.0 }))
                    .expect("read to write");
            }
        });

        futures::finished(self).boxed()
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        self.recv_raw_frame()
            .and_then(move |(rl, frame)| rl.process_raw_frame(frame))
            .boxed()
    }

    fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |rl, _| {
            rl.read_process_frame()
        });

        future.map(|_| ()).boxed()
    }
}

impl<H : ResponseHandler> HttpConnectionAsync<H> {
    fn new(lh: LoopHandle, conn: TcpStream) -> HttpFuture<(Self, HttpFuture<()>)> {
        let (call_tx, call_rx) = lh.channel();

        let handshake = client_handshake(conn);
        handshake.and_then(move |conn| {
            let (read, write) = TaskIo::new(conn).split();

            let inner = TaskRcMut::new(Inner {
                host: "localhost".to_owned(), // TODO
                conn: HttpConnection::new(HttpScheme::Http),
                call_tx: call_tx,
                session_state: MySessionState {
                    next_stream_id: 1,
                    streams: HashMap::new(),
                }
            });

            let write_inner = inner.clone();
            let run_write = call_rx.map_err(HttpError::from).and_then(move |call_rx| WriteLoop { write: write, inner: write_inner }.run(call_rx));
            let run_read = ReadLoop { read: read, inner: inner.clone() }.run();

            let c = HttpConnectionAsync {
                inner: inner,
            };
            Ok((c, run_write.join(run_read).map(|_| ()).boxed()))
        }).boxed()
    }

    fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpStream<Vec<u8>>,
        response_handler: H)
            -> HttpFuture<()>
    {
        self.inner.with(|inner: &mut Inner<H>| {
            inner.call_tx.send(ToWriteMessage::Start(StartRequestMessage {
                headers: headers,
                body: body,
                response_handler: response_handler,
            }));
        });
        futures::finished(()).boxed()
    }
}
<commit_msg>more http client<commit_after>use std::marker;
use std::cmp;
use std::mem;
use std::collections::HashMap;
use std::iter::FromIterator;

use solicit::http::client::RequestStream;
use solicit::http::client::ClientSession;
use solicit::http::session::Client;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataError;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::Stream as solicit_Stream;
use solicit::http::session::StreamIter;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::SendStatus;
use solicit::http::connection::EndStream;
use solicit::http::connection::DataChunk;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::frame::RawFrame;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::TaskIo;
use tokio_core::io::TaskIoRead;
use tokio_core::io::TaskIoWrite;
use tokio_core::LoopHandle;

use error::*;
use futures_misc::*;

use solicit_async::*;
use solicit_misc::*;

// TODO: make async
trait ResponseHandler : Send + 'static {
    fn headers(&mut self, headers: Vec<StaticHeader>);
    fn body_chunk(&mut self, chunk: Vec<u8>);
    fn trailers(&mut self, headers: Vec<StaticHeader>);
    fn end(&mut self);
}

enum ResponseState {
    Init,
    GotHeaders,
    GotBodyChunk,
    GotTrailers,
}

enum LastChunk {
    Empty,
    Headers(Vec<StaticHeader>),
    Chunk(Vec<u8>),
    Trailers(Vec<StaticHeader>),
}

struct GrpcHttp2ClientStream2<H : ResponseHandler> {
    state: StreamState,
    response_state: ResponseState,
    last_chunk: LastChunk,
    response_handler: Option<H>,
}

impl<H : ResponseHandler> solicit_Stream for GrpcHttp2ClientStream2<H> {
    fn set_headers<'n, 'v>(&mut self, headers: Vec<Header<'n, 'v>>) {
        let headers = headers.into_iter().map(|h| Header::new(h.name().to_owned(), h.value().to_owned())).collect();
        self.last_chunk = LastChunk::Headers(headers);
        self.response_state = match self.response_state {
            ResponseState::Init => ResponseState::GotHeaders,
            ResponseState::GotHeaders => panic!(),
            ResponseState::GotBodyChunk => ResponseState::GotTrailers,
            ResponseState::GotTrailers => panic!(),
        };
    }

    fn new_data_chunk(&mut self, data: &[u8]) {
        self.last_chunk = LastChunk::Chunk(data.to_owned());
    }

    fn set_state(&mut self, state: StreamState) {
        self.state = state;
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        unimplemented!()
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

struct MySessionState<H : ResponseHandler> {
    streams: HashMap<StreamId, GrpcHttp2ClientStream2<H>>,
    next_stream_id: StreamId,
}

impl<H : ResponseHandler> MySessionState<H> {
    fn process_streams_after_handle_next_frame(&mut self) {
        let mut remove_ids = Vec::new();

        for (id, s) in &mut self.streams {
            let last_chunk = mem::replace(&mut s.last_chunk, LastChunk::Empty);
            match last_chunk {
                LastChunk::Empty => (),
                LastChunk::Chunk(chunk) => {
                    s.response_handler.as_mut().unwrap().body_chunk(chunk);
                }
                LastChunk::Headers(headers) => {
                    s.response_handler.as_mut().unwrap().headers(headers);
                }
                LastChunk::Trailers(headers) => {
                    s.response_handler.as_mut().unwrap().trailers(headers);
                }
            }

            if s.is_closed() {
                remove_ids.push(*id);
            }
        }

        Vec::from_iter(remove_ids.into_iter().map(|i| self.remove_stream(i).unwrap()));
    }
}

impl<H : ResponseHandler> SessionState for MySessionState<H> {
    type Stream = GrpcHttp2ClientStream2<H>;

    fn insert_outgoing(&mut self, stream: Self::Stream) -> StreamId {
        let id = self.next_stream_id;
        self.streams.insert(id, stream);
        self.next_stream_id += 2;
        id
    }

    fn insert_incoming(&mut self, stream_id: StreamId, stream: Self::Stream) -> Result<(), ()> {
        // TODO: assert parity
        // TODO: Assert that the stream IDs are monotonically increasing!
        self.streams.insert(stream_id, stream);
        Ok(())
    }

    #[inline]
    fn get_stream_ref(&self, stream_id: StreamId) -> Option<&Self::Stream> {
        self.streams.get(&stream_id)
    }

    #[inline]
    fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut Self::Stream> {
        self.streams.get_mut(&stream_id)
    }

    #[inline]
    fn remove_stream(&mut self, stream_id: StreamId) -> Option<Self::Stream> {
        self.streams.remove(&stream_id)
    }

    #[inline]
    fn iter(&mut self) -> StreamIter<GrpcHttp2ClientStream2<H>> {
        // https://github.com/mlalic/solicit/pull/34
        unimplemented!()
    }

    /// Number of currently active streams
    #[inline]
    fn len(&self) -> usize {
        self.streams.len()
    }
}

struct Inner<H : ResponseHandler> {
    host: String,
    conn: HttpConnection,
    call_tx: tokio_core::Sender<ToWriteMessage<H>>,
    session_state: MySessionState<H>,
}

struct HttpConnectionAsync<H : ResponseHandler> {
    inner: TaskRcMut<Inner<H>>,
}

struct StartRequestMessage<H : ResponseHandler> {
    headers: Vec<StaticHeader>,
    body: HttpStream<Vec<u8>>,
    response_handler: H,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

struct ReadToWriteMessage {
    buf: Vec<u8>,
}

enum ToWriteMessage<H : ResponseHandler> {
    Start(StartRequestMessage<H>),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    FromRead(ReadToWriteMessage),
}

struct WriteLoop<H : ResponseHandler> {
    write: TaskIoWrite<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> WriteLoop<H> {
    fn write_all(self, buf: Vec<u8>) -> HttpFuture<Self> {
        let WriteLoop { write, inner } = self;

        tokio_io::write_all(write, buf)
            .map(move |(write, _)| WriteLoop { write: write, inner: inner })
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_from_read(self, message: ReadToWriteMessage) -> HttpFuture<Self> {
        self.write_all(message.buf)
    }

    fn process_start(self, start: StartRequestMessage<H>) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;
        let (buf, stream_id) = self.inner.with(move |inner: &mut Inner<H>| {

            let stream = GrpcHttp2ClientStream2 {
                state: StreamState::Open,
                response_handler: Some(response_handler),
                last_chunk: LastChunk::Empty,
                response_state: ResponseState::Init,
            };
            let stream_id = inner.session_state.insert_outgoing(stream);

            let send_buf = {
                let mut send_buf = VecSendFrame(Vec::new());

                inner.conn.sender(&mut send_buf).send_headers(headers, stream_id, EndStream::No).unwrap();

                (send_buf.0, stream_id)
            };

            send_buf
        });

        self.write_all(buf)
            .and_then(move |wl: WriteLoop<H>| {
                body.fold(wl, move |wl: WriteLoop<H>, chunk| {
                    wl.inner.with(|inner: &mut Inner<H>| {
                        inner.call_tx.send(ToWriteMessage::BodyChunk(BodyChunkMessage {
                            stream_id: stream_id,
                            chunk: chunk,
                        }))
                    });
                    futures::finished::<_, HttpError>(wl)
                })
            })
            .and_then(move |wl: WriteLoop<H>| {
                wl.inner.with(|inner: &mut Inner<H>| {
                    inner.call_tx.send(ToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    }));
                });
                futures::finished::<_, HttpError>(wl)
            })
            .boxed()
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            {
                let stream = inner.session_state.get_stream_mut(stream_id);
                // TODO: check stream state
            }

            let mut send_buf = VecSendFrame(Vec::new());

            let mut pos = 0;
            const MAX_CHUNK_SIZE: usize = 8 * 1024;
            while pos < chunk.len() {
                let end = cmp::min(chunk.len(), pos + MAX_CHUNK_SIZE);

                let data_chunk = DataChunk::new_borrowed(&chunk[pos..end], stream_id, EndStream::No);

                inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

                pos = end;
            }

            send_buf.0
        });

        self.write_all(buf)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            let mut send_buf = VecSendFrame(Vec::new());

            let chunk = Vec::new();
            let data_chunk = DataChunk::new_borrowed(&chunk[..], stream_id, EndStream::Yes);

            inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

            send_buf.0
        });

        futures::finished(self).boxed()
    }

    fn process_message(self, message: ToWriteMessage<H>) -> HttpFuture<Self> {
        match message {
            ToWriteMessage::Start(start) => self.process_start(start),
            ToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ToWriteMessage::End(end) => self.process_end(end),
            ToWriteMessage::FromRead(from_read) => self.process_from_read(from_read),
        }
    }

    fn run(self, requests: tokio_core::Receiver<ToWriteMessage<H>>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        requests
            .fold(self, move |wl, message: ToWriteMessage<H>| {
                wl.process_message(message)
            })
            .map(|_| ())
            .boxed()
    }
}

struct ReadLoop<H : ResponseHandler> {
    read: TaskIoRead<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> ReadLoop<H> {
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let ReadLoop { read, inner } = self;
        recv_raw_frame(read)
            .map(|(read, frame)| (ReadLoop { read: read, inner: inner}, frame))
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_streams_after_handle_next_frame(self) -> HttpFuture<Self> {
        self.inner.with(|inner: &mut Inner<H>| {
            inner.session_state.process_streams_after_handle_next_frame();
        });

        futures::finished(self).boxed()
    }

    fn process_raw_frame(self, raw_frame: RawFrame) -> HttpFuture<Self> {
        self.inner.with(move |inner: &mut Inner<H>| {
            let mut send = VecSendFrame(Vec::new());
            {
                let mut session = ClientSession::new(&mut inner.session_state, &mut send);
                inner.conn.handle_next_frame(&mut OnceReceiveFrame::new(raw_frame), &mut session)
                    .unwrap();
            }

            if !send.0.is_empty() {
                inner.call_tx.send(ToWriteMessage::FromRead(ReadToWriteMessage { buf: send.0 }))
                    .expect("read to write");
            }
        });

        self.process_streams_after_handle_next_frame()
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        self.recv_raw_frame()
            .and_then(move |(rl, frame)| rl.process_raw_frame(frame))
            .boxed()
    }

    fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |rl, _| {
            rl.read_process_frame()
        });

        future.map(|_| ()).boxed()
    }
}

impl<H : ResponseHandler> HttpConnectionAsync<H> {
    fn new(lh: LoopHandle, conn: TcpStream) -> HttpFuture<(Self, HttpFuture<()>)> {
        let (call_tx, call_rx) = lh.channel();

        let handshake = client_handshake(conn);
        handshake.and_then(move |conn| {
            let (read, write) = TaskIo::new(conn).split();

            let inner = TaskRcMut::new(Inner {
                host: "localhost".to_owned(), // TODO
                conn: HttpConnection::new(HttpScheme::Http),
                call_tx: call_tx,
                session_state: MySessionState {
                    next_stream_id: 1,
                    streams: HashMap::new(),
                }
            });

            let write_inner = inner.clone();
            let run_write = call_rx.map_err(HttpError::from).and_then(move |call_rx| WriteLoop { write: write, inner: write_inner }.run(call_rx));
            let run_read = ReadLoop { read: read, inner: inner.clone() }.run();

            let c = HttpConnectionAsync {
                inner: inner,
            };
            Ok((c, run_write.join(run_read).map(|_| ()).boxed()))
        }).boxed()
    }

    fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpStream<Vec<u8>>,
        response_handler: H)
            -> HttpFuture<()>
    {
        self.inner.with(|inner: &mut Inner<H>| {
            inner.call_tx.send(ToWriteMessage::Start(StartRequestMessage {
                headers: headers,
                body: body,
                response_handler: response_handler,
            }));
        });
        futures::finished(()).boxed()
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use futures::stream::Stream;
use futures::Future;
use futures;

use tokio_core::io::ReadHalf;
use tokio_core::io::Io;

use solicit::http::session::StreamState;
use solicit::http::frame::*;
use solicit::http::StaticHeader;
use solicit::http::StreamId;
use solicit::http::HttpError;
use solicit::http::WindowSize;
use solicit::http::HttpScheme;
use solicit::http::INITIAL_CONNECTION_WINDOW_SIZE;
use solicit::http::connection::HttpConnection;

use futures_misc::*;

use solicit_misc::*;
use solicit_async::*;

#[derive(Debug)]
pub enum HttpStreamPartContent {
    Headers(Vec<StaticHeader>),
    Data(Vec<u8>),
}

pub struct HttpStreamPart {
    pub content: HttpStreamPartContent,
    /// END_STREAM
    pub last: bool,
}

impl HttpStreamPart {
    pub fn last_headers(header: Vec<StaticHeader>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Headers(header),
            last: true,
        }
    }

    pub fn intermediate_headers(headers: Vec<StaticHeader>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Headers(headers),
            last: false,
        }
    }

    pub fn intermediate_data(data: Vec<u8>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Data(data),
            last: false,
        }
    }

    pub fn last_data(data: Vec<u8>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Data(data),
            last: true,
        }
    }
}

pub type HttpStreamStream = Box<Stream<Item=HttpStreamPart, Error=HttpError>>;
pub type HttpStreamStreamSend = Box<Stream<Item=HttpStreamPart, Error=HttpError> + Send>;

pub trait HttpService: Send + 'static {
    fn new_request(&mut self, headers: Vec<StaticHeader>, req: HttpStreamStreamSend) -> HttpStreamStreamSend;
}

pub struct GrpcHttpStreamCommon {
    pub state: StreamState,
    pub out_window_size: WindowSize,
    pub in_window_size: WindowSize,
}

impl GrpcHttpStreamCommon {
    pub fn new() -> GrpcHttpStreamCommon {
        GrpcHttpStreamCommon {
            state: StreamState::Open,
            in_window_size: WindowSize::new(INITIAL_CONNECTION_WINDOW_SIZE),
            out_window_size: WindowSize::new(INITIAL_CONNECTION_WINDOW_SIZE),
        }
    }
}

pub trait GrpcHttpStream {
    fn common(&self) -> &GrpcHttpStreamCommon;
    fn common_mut(&mut self) -> &mut GrpcHttpStreamCommon;
    fn new_data_chunk(&mut self, data: &[u8], last: bool);
    fn close_remote(&mut self);
}

pub struct LoopInnerCommon<S>
    where S : GrpcHttpStream,
{
    pub conn: HttpConnection,
    pub streams: HashMap<StreamId, S>,
}

impl<S> LoopInnerCommon<S>
    where S : GrpcHttpStream,
{
    pub fn new(scheme: HttpScheme) -> LoopInnerCommon<S> {
        LoopInnerCommon {
            conn: HttpConnection::new(scheme),
            streams: HashMap::new(),
        }
    }

    pub fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut S> {
        self.streams.get_mut(&stream_id)
    }

    pub fn remove_stream(&mut self, stream_id: StreamId) -> Option<S> {
        self.streams.remove(&stream_id)
    }

    pub fn remove_stream_if_closed(&mut self, stream_id: StreamId) {
        if self.get_stream_mut(stream_id).expect("unknown stream").common().state == StreamState::Closed {
            self.remove_stream(stream_id);
        }
    }
}

pub trait HttpReadLoopInner : 'static {
    type LoopHttpStream : GrpcHttpStream;

    fn common(&mut self) -> &mut LoopInnerCommon<Self::LoopHttpStream>;

    /// Send a frame back to the network
    /// Must not be data frame
    fn send_frame<R : FrameIR>(&mut self, frame: R);
    fn out_window_increased(&mut self, stream_id: Option<StreamId>);

    fn process_headers_frame(&mut self, frame: HeadersFrame);

    fn process_settings_global(&mut self, _frame: SettingsFrame) {
        // TODO: apply settings
        // TODO: send ack
    }

    fn process_stream_window_update_frame(&mut self, frame: WindowUpdateFrame) {
        {
            match self.common().get_stream_mut(frame.get_stream_id()) {
                Some(stream) => {
                    stream.common_mut().out_window_size.try_increase(frame.increment())
                        .expect("failed to increment stream window");
                }
                None => {
                    // 6.9
                    // WINDOW_UPDATE can be sent by a peer that has sent a frame bearing the
                    // END_STREAM flag.  This means that a receiver could receive a
                    // WINDOW_UPDATE frame on a "half-closed (remote)" or "closed" stream.
                    // A receiver MUST NOT treat this as an error (see Section 5.1).
                    debug!("WINDOW_UPDATE of unknown stream: {}", frame.get_stream_id());
                }
            }
        }
        self.out_window_increased(Some(frame.get_stream_id()));
    }

    fn process_conn_window_update(&mut self, frame: WindowUpdateFrame) {
        self.common().conn.out_window_size.try_increase(frame.increment())
            .expect("failed to increment conn window");
        self.out_window_increased(None);
    }

    fn process_rst_stream_frame(&mut self, _frame: RstStreamFrame) {
    }

    fn process_data_frame(&mut self, frame: DataFrame) {
        let stream_id = frame.get_stream_id();

        self.common().conn.decrease_in_window(frame.payload_len())
            .expect("failed to decrease conn win");

        let increment_conn =
            if self.common().conn.in_window_size() < INITIAL_CONNECTION_WINDOW_SIZE / 2 {
                let increment = INITIAL_CONNECTION_WINDOW_SIZE as u32;
                self.common().conn.in_window_size.try_increase(increment).expect("failed to increase");

                Some(increment)
            } else {
                None
            };

        let increment_stream = {
            let stream = self.common().get_stream_mut(frame.get_stream_id())
                .expect(&format!("stream not found: {}", frame.get_stream_id()));

            stream.common_mut().in_window_size.try_decrease(frame.payload_len() as i32)
                .expect("failed to decrease stream win");

            let increment_stream =
                if stream.common_mut().in_window_size.size() < INITIAL_CONNECTION_WINDOW_SIZE / 2 {
                    let increment = INITIAL_CONNECTION_WINDOW_SIZE as u32;
                    stream.common_mut().in_window_size.try_increase(increment).expect("failed to increase");

                    Some(increment)
                } else {
                    None
                };

            stream.new_data_chunk(&frame.data.as_ref(), frame.is_end_of_stream());

            if frame.is_end_of_stream() {
                stream.close_remote();
                // TODO: GC streams
            }

            // TODO: drop stream if closed on both ends

            increment_stream
        };

        if let Some(increment_conn) = increment_conn {
            self.send_frame(WindowUpdateFrame::for_connection(increment_conn));
        }

        if let Some(increment_stream) = increment_stream {
            self.send_frame(WindowUpdateFrame::for_stream(stream_id, increment_stream));
        }
    }

    fn process_ping(&mut self, frame: PingFrame) {
        if frame.is_ack() {

        } else {
            self.send_frame(PingFrame::new_ack(frame.opaque_data()));
        }
    }

    fn process_conn_frame(&mut self, frame: HttpFrameConn) {
        match frame {
            HttpFrameConn::Settings(f) => self.process_settings_global(f),
            HttpFrameConn::Ping(f) => self.process_ping(f),
            HttpFrameConn::Goaway(_f) => panic!("TODO"),
            HttpFrameConn::WindowUpdate(f) => self.process_conn_window_update(f),
        }
    }

    fn process_stream_frame(&mut self, frame: HttpFrameStream) {
        let stream_id = frame.get_stream_id();
        let end_of_stream = frame.is_end_of_stream();
        match frame {
            HttpFrameStream::Data(data) => self.process_data_frame(data),
            HttpFrameStream::Headers(headers) => self.process_headers_frame(headers),
            HttpFrameStream::RstStream(rst) => self.process_rst_stream_frame(rst),
            HttpFrameStream::WindowUpdate(window_update) => self.process_stream_window_update_frame(window_update),
        };
        if end_of_stream {
            self.close_remote(stream_id);
        }
    }

    fn process_raw_frame(&mut self, raw_frame: RawFrame) {
        let frame = HttpFrameClassified::from_raw(&raw_frame).unwrap();
        debug!("received frame: {:?}", frame);
        match frame {
            HttpFrameClassified::Conn(f) => self.process_conn_frame(f),
            HttpFrameClassified::Stream(f) => self.process_stream_frame(f),
            HttpFrameClassified::Unknown(_f) => {},
        }
    }

    fn close_remote(&mut self, stream_id: StreamId) {
        debug!("close remote: {}", stream_id);

        let remove = {
            let mut stream = self.common().get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));
            stream.close_remote();
            stream.common().state == StreamState::Closed
        };
        if remove {
            self.common().remove_stream(stream_id);
        }
    }
}

pub struct HttpReadLoopData<I, N>
    where
        I : Io + 'static,
        N : HttpReadLoopInner,
{
    pub read: ReadHalf<I>,
    pub inner: TaskRcMut<N>,
}

impl<I, N> HttpReadLoopData<I, N>
    where
        I : Io + Send + 'static,
        N : HttpReadLoopInner,
{
    /// Recv a frame from the network
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let HttpReadLoopData { read, inner } = self;
        Box::new(recv_raw_frame(read)
            .map(|(read, frame)| (HttpReadLoopData { read: read, inner: inner }, frame))
            .map_err(HttpError::from))
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        Box::new(self.recv_raw_frame()
            .and_then(move |(lp, frame)| lp.process_raw_frame(frame)))
    }

    pub fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |lp, _| {
            lp.read_process_frame()
        });

        Box::new(future.map(|_| ()))
    }

    fn process_raw_frame(self, frame: RawFrame) -> HttpFuture<Self> {
        self.inner.with(move |inner| {
            inner.process_raw_frame(frame);
        });
        Box::new(futures::finished(self))
    }

}
<commit_msg>ack SETTINGS frame<commit_after>use std::collections::HashMap;

use futures::stream::Stream;
use futures::Future;
use futures;

use tokio_core::io::ReadHalf;
use tokio_core::io::Io;

use solicit::http::session::StreamState;
use solicit::http::frame::*;
use solicit::http::StaticHeader;
use solicit::http::StreamId;
use solicit::http::HttpError;
use solicit::http::WindowSize;
use solicit::http::HttpScheme;
use solicit::http::INITIAL_CONNECTION_WINDOW_SIZE;
use solicit::http::connection::HttpConnection;

use futures_misc::*;

use solicit_misc::*;
use solicit_async::*;

#[derive(Debug)]
pub enum HttpStreamPartContent {
    Headers(Vec<StaticHeader>),
    Data(Vec<u8>),
}

pub struct HttpStreamPart {
    pub content: HttpStreamPartContent,
    /// END_STREAM
    pub last: bool,
}

impl HttpStreamPart {
    pub fn last_headers(header: Vec<StaticHeader>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Headers(header),
            last: true,
        }
    }

    pub fn intermediate_headers(headers: Vec<StaticHeader>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Headers(headers),
            last: false,
        }
    }

    pub fn intermediate_data(data: Vec<u8>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Data(data),
            last: false,
        }
    }

    pub fn last_data(data: Vec<u8>) -> Self {
        HttpStreamPart {
            content: HttpStreamPartContent::Data(data),
            last: true,
        }
    }
}

pub type HttpStreamStream = Box<Stream<Item=HttpStreamPart, Error=HttpError>>;
pub type HttpStreamStreamSend = Box<Stream<Item=HttpStreamPart, Error=HttpError> + Send>;

pub trait HttpService: Send + 'static {
    fn new_request(&mut self, headers: Vec<StaticHeader>, req: HttpStreamStreamSend) -> HttpStreamStreamSend;
}

pub struct GrpcHttpStreamCommon {
    pub state: StreamState,
    pub out_window_size: WindowSize,
    pub in_window_size: WindowSize,
}

impl GrpcHttpStreamCommon {
    pub fn new() -> GrpcHttpStreamCommon {
        GrpcHttpStreamCommon {
            state: StreamState::Open,
            in_window_size: WindowSize::new(INITIAL_CONNECTION_WINDOW_SIZE),
            out_window_size: WindowSize::new(INITIAL_CONNECTION_WINDOW_SIZE),
        }
    }
}

pub trait GrpcHttpStream {
    fn common(&self) -> &GrpcHttpStreamCommon;
    fn common_mut(&mut self) -> &mut GrpcHttpStreamCommon;
    fn new_data_chunk(&mut self, data: &[u8], last: bool);
    fn close_remote(&mut self);
}

pub struct LoopInnerCommon<S>
    where S : GrpcHttpStream,
{
    pub conn: HttpConnection,
    pub streams: HashMap<StreamId, S>,
}

impl<S> LoopInnerCommon<S>
    where S : GrpcHttpStream,
{
    pub fn new(scheme: HttpScheme) -> LoopInnerCommon<S> {
        LoopInnerCommon {
            conn: HttpConnection::new(scheme),
            streams: HashMap::new(),
        }
    }

    pub fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut S> {
        self.streams.get_mut(&stream_id)
    }

    pub fn remove_stream(&mut self, stream_id: StreamId) -> Option<S> {
        self.streams.remove(&stream_id)
    }

    pub fn remove_stream_if_closed(&mut self, stream_id: StreamId) {
        if self.get_stream_mut(stream_id).expect("unknown stream").common().state == StreamState::Closed {
            self.remove_stream(stream_id);
        }
    }
}

pub trait HttpReadLoopInner : 'static {
    type LoopHttpStream : GrpcHttpStream;

    fn common(&mut self) -> &mut LoopInnerCommon<Self::LoopHttpStream>;

    /// Send a frame back to the network
    /// Must not be data frame
    fn send_frame<R : FrameIR>(&mut self, frame: R);
    fn out_window_increased(&mut self, stream_id: Option<StreamId>);

    /// Sends an SETTINGS Frame with ack set to acknowledge seeing a SETTINGS frame from the peer.
    fn ack_settings(&mut self) {
        self.send_frame(SettingsFrame::new_ack());
    }

    fn process_headers_frame(&mut self, frame: HeadersFrame);

    fn process_settings_global(&mut self, _frame: SettingsFrame) {
        // TODO: apply settings

        self.ack_settings();
    }

    fn process_stream_window_update_frame(&mut self, frame: WindowUpdateFrame) {
        {
            match self.common().get_stream_mut(frame.get_stream_id()) {
                Some(stream) => {
                    stream.common_mut().out_window_size.try_increase(frame.increment())
                        .expect("failed to increment stream window");
                }
                None => {
                    // 6.9
                    // WINDOW_UPDATE can be sent by a peer that has sent a frame bearing the
                    // END_STREAM flag.  This means that a receiver could receive a
                    // WINDOW_UPDATE frame on a "half-closed (remote)" or "closed" stream.
                    // A receiver MUST NOT treat this as an error (see Section 5.1).
                    debug!("WINDOW_UPDATE of unknown stream: {}", frame.get_stream_id());
                }
            }
        }
        self.out_window_increased(Some(frame.get_stream_id()));
    }

    fn process_conn_window_update(&mut self, frame: WindowUpdateFrame) {
        self.common().conn.out_window_size.try_increase(frame.increment())
            .expect("failed to increment conn window");
        self.out_window_increased(None);
    }

    fn process_rst_stream_frame(&mut self, _frame: RstStreamFrame) {
    }

    fn process_data_frame(&mut self, frame: DataFrame) {
        let stream_id = frame.get_stream_id();

        self.common().conn.decrease_in_window(frame.payload_len())
            .expect("failed to decrease conn win");

        let increment_conn =
            if self.common().conn.in_window_size() < INITIAL_CONNECTION_WINDOW_SIZE / 2 {
                let increment = INITIAL_CONNECTION_WINDOW_SIZE as u32;
                self.common().conn.in_window_size.try_increase(increment).expect("failed to increase");

                Some(increment)
            } else {
                None
            };

        let increment_stream = {
            let stream = self.common().get_stream_mut(frame.get_stream_id())
                .expect(&format!("stream not found: {}", frame.get_stream_id()));

            stream.common_mut().in_window_size.try_decrease(frame.payload_len() as i32)
                .expect("failed to decrease stream win");

            let increment_stream =
                if stream.common_mut().in_window_size.size() < INITIAL_CONNECTION_WINDOW_SIZE / 2 {
                    let increment = INITIAL_CONNECTION_WINDOW_SIZE as u32;
                    stream.common_mut().in_window_size.try_increase(increment).expect("failed to increase");

                    Some(increment)
                } else {
                    None
                };

            stream.new_data_chunk(&frame.data.as_ref(), frame.is_end_of_stream());

            if frame.is_end_of_stream() {
                stream.close_remote();
                // TODO: GC streams
            }

            // TODO: drop stream if closed on both ends

            increment_stream
        };

        if let Some(increment_conn) = increment_conn {
            self.send_frame(WindowUpdateFrame::for_connection(increment_conn));
        }

        if let Some(increment_stream) = increment_stream {
            self.send_frame(WindowUpdateFrame::for_stream(stream_id, increment_stream));
        }
    }

    fn process_ping(&mut self, frame: PingFrame) {
        if frame.is_ack() {

        } else {
            self.send_frame(PingFrame::new_ack(frame.opaque_data()));
        }
    }

    fn process_conn_frame(&mut self, frame: HttpFrameConn) {
        match frame {
            HttpFrameConn::Settings(f) => self.process_settings_global(f),
            HttpFrameConn::Ping(f) => self.process_ping(f),
            HttpFrameConn::Goaway(_f) => panic!("TODO"),
            HttpFrameConn::WindowUpdate(f) => self.process_conn_window_update(f),
        }
    }

    fn process_stream_frame(&mut self, frame: HttpFrameStream) {
        let stream_id = frame.get_stream_id();
        let end_of_stream = frame.is_end_of_stream();
        match frame {
            HttpFrameStream::Data(data) => self.process_data_frame(data),
            HttpFrameStream::Headers(headers) => self.process_headers_frame(headers),
            HttpFrameStream::RstStream(rst) => self.process_rst_stream_frame(rst),
            HttpFrameStream::WindowUpdate(window_update) => self.process_stream_window_update_frame(window_update),
        };
        if end_of_stream {
            self.close_remote(stream_id);
        }
    }

    fn process_raw_frame(&mut self, raw_frame: RawFrame) {
        let frame = HttpFrameClassified::from_raw(&raw_frame).unwrap();
        debug!("received frame: {:?}", frame);
        match frame {
            HttpFrameClassified::Conn(f) => self.process_conn_frame(f),
            HttpFrameClassified::Stream(f) => self.process_stream_frame(f),
            HttpFrameClassified::Unknown(_f) => {},
        }
    }

    fn close_remote(&mut self, stream_id: StreamId) {
        debug!("close remote: {}", stream_id);

        let remove = {
            let mut stream = self.common().get_stream_mut(stream_id)
                .expect(&format!("stream not found: {}", stream_id));
            stream.close_remote();
            stream.common().state == StreamState::Closed
        };
        if remove {
            self.common().remove_stream(stream_id);
        }
    }
}

pub struct HttpReadLoopData<I, N>
    where
        I : Io + 'static,
        N : HttpReadLoopInner,
{
    pub read: ReadHalf<I>,
    pub inner: TaskRcMut<N>,
}

impl<I, N> HttpReadLoopData<I, N>
    where
        I : Io + Send + 'static,
        N : HttpReadLoopInner,
{
    /// Recv a frame from the network
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let HttpReadLoopData { read, inner } = self;
        Box::new(recv_raw_frame(read)
            .map(|(read, frame)| (HttpReadLoopData { read: read, inner: inner }, frame))
            .map_err(HttpError::from))
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        Box::new(self.recv_raw_frame()
            .and_then(move |(lp, frame)| lp.process_raw_frame(frame)))
    }

    pub fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |lp, _| {
            lp.read_process_frame()
        });

        Box::new(future.map(|_| ()))
    }

    fn process_raw_frame(self, frame: RawFrame) -> HttpFuture<Self> {
        self.inner.with(move |inner| {
            inner.process_raw_frame(frame);
        });
        Box::new(futures::finished(self))
    }

}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing utilities for writing procedural macros.

extern crate syntax;

use syntax::parse::{ParseSess, filemap_to_tts};
use syntax::tokenstream::TokenStream;

/// Map a string to tts, using a made-up filename. For example, `lex(15)` will return a
/// TokenStream containing the literal 15.
pub fn lex(source_str: &str) -> TokenStream {
    let ps = ParseSess::new();
    TokenStream::from_tts(filemap_to_tts(&ps,
                                         ps.codemap().new_filemap("procmacro_lex".to_string(),
                                                                  None,
                                                                  source_str.to_owned())))
}
<commit_msg>Auto merge of #37186 - jonas-schievink:patch-1, r=brson<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parsing utilities for writing procedural macros.

extern crate syntax;

use syntax::parse::{ParseSess, filemap_to_tts};
use syntax::tokenstream::TokenStream;

/// Map a string to tts, using a made-up filename. For example, `lex("15")` will return a
/// TokenStream containing the literal 15.
pub fn lex(source_str: &str) -> TokenStream {
    let ps = ParseSess::new();
    TokenStream::from_tts(filemap_to_tts(&ps,
                                         ps.codemap().new_filemap("<procmacro_lex>".to_string(),
                                                                  None,
                                                                  source_str.to_owned())))
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::ty::TypeFoldable;
use rustc::ty::subst::{Kind, Substs};
use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind};
use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, Lookup};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::infer::{self, InferCtxt};
use syntax_pos::DUMMY_SP;
use std::collections::HashMap;

#[allow(dead_code)]
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
    pub lookup_map: HashMap<RegionVid, Lookup>,
    infcx: InferCtxt<'a, 'gcx, 'tcx>,
}

impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
    pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
        NLLVisitor {
            infcx: infcx,
            lookup_map: HashMap::new(),
        }
    }

    fn renumber_regions<T>(&self, value: &T) -> T where T: TypeFoldable<'tcx> {
        self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
            self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP))
        })
    }

    fn store_region(&mut self, region: &RegionKind, lookup: Lookup) {
        if let RegionKind::ReVar(rid) = *region {
            self.lookup_map.entry(rid).or_insert(lookup);
        }
    }

    fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) {
        for region in ty.regions() {
            self.store_region(region, lookup);
        }
    }

    fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) {
        if let Some(ty) = kind.as_type() {
            self.store_ty_regions(&ty, lookup);
        } else if let Some(region) = kind.as_region() {
            self.store_region(region, lookup);
        }
    }
}

impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) {
        let old_ty = *ty;
        *ty = self.renumber_regions(&old_ty);
        self.store_ty_regions(ty, lookup);
    }

    fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
        *substs = self.renumber_regions(&{*substs});
        let lookup = Lookup::Loc(location);
        for kind in *substs {
            self.store_kind_regions(kind, lookup);
        }
    }

    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
        match *rvalue {
            Rvalue::Ref(ref mut r, _, _) => {
                let old_r = *r;
                *r = self.renumber_regions(&old_r);
                let lookup = Lookup::Loc(location);
                self.store_region(r, lookup);
            }
            Rvalue::Use(..) |
            Rvalue::Repeat(..) |
            Rvalue::Len(..) |
            Rvalue::Cast(..) |
            Rvalue::BinaryOp(..) |
            Rvalue::CheckedBinaryOp(..) |
            Rvalue::UnaryOp(..) |
            Rvalue::Discriminant(..) |
            Rvalue::NullaryOp(..) |
            Rvalue::Aggregate(..) => {
                // These variants don't contain regions.
            }
        }
        self.super_rvalue(rvalue, location);
    }

    fn visit_closure_substs(&mut self,
                            substs: &mut ClosureSubsts<'tcx>,
                            location: Location) {
        *substs = self.renumber_regions(substs);
        let lookup = Lookup::Loc(location);
        for kind in substs.substs {
            self.store_kind_regions(kind, lookup);
        }
    }

    fn visit_statement(&mut self,
                       block: BasicBlock,
                       statement: &mut Statement<'tcx>,
                       location: Location) {
        if let StatementKind::EndRegion(_) = statement.kind {
            statement.kind = StatementKind::Nop;
        }
        self.super_statement(block, statement, location);
    }
}

// MIR Pass for non-lexical lifetimes
pub struct NLL;

impl MirPass for NLL {
    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          _: MirSource,
                          mir: &mut Mir<'tcx>) {
        if !tcx.sess.opts.debugging_opts.nll {
            return;
        }

        tcx.infer_ctxt().enter(|infcx| {
            // Clone mir so we can mutate it without disturbing the rest of the compiler
            let mut renumbered_mir = mir.clone();
            let mut visitor = NLLVisitor::new(infcx);
            visitor.visit_mir(&mut renumbered_mir);
        })
    }
}<commit_msg>Keep map hidden and instead move it out after visitor is finished<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::ty::TypeFoldable;
use rustc::ty::subst::{Kind, Substs};
use rustc::ty::{Ty, TyCtxt, ClosureSubsts, RegionVid, RegionKind};
use rustc::mir::{Mir, Location, Rvalue, BasicBlock, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, Lookup};
use rustc::mir::transform::{MirPass, MirSource};
use rustc::infer::{self, InferCtxt};
use syntax_pos::DUMMY_SP;
use std::collections::HashMap;

#[allow(dead_code)]
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
    lookup_map: HashMap<RegionVid, Lookup>,
    infcx: InferCtxt<'a, 'gcx, 'tcx>,
}

impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
    pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
        NLLVisitor {
            infcx: infcx,
            lookup_map: HashMap::new(),
        }
    }

    pub fn into_results(self) -> HashMap<RegionVid, Lookup> {
        self.lookup_map
    }

    fn renumber_regions<T>(&self, value: &T) -> T where T: TypeFoldable<'tcx> {
        self.infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
            self.infcx.next_region_var(infer::MiscVariable(DUMMY_SP))
        })
    }

    fn store_region(&mut self, region: &RegionKind, lookup: Lookup) {
        if let RegionKind::ReVar(rid) = *region {
            self.lookup_map.entry(rid).or_insert(lookup);
        }
    }

    fn store_ty_regions(&mut self, ty: &Ty<'tcx>, lookup: Lookup) {
        for region in ty.regions() {
            self.store_region(region, lookup);
        }
    }

    fn store_kind_regions(&mut self, kind: &'tcx Kind, lookup: Lookup) {
        if let Some(ty) = kind.as_type() {
            self.store_ty_regions(&ty, lookup);
        } else if let Some(region) = kind.as_region() {
            self.store_region(region, lookup);
        }
    }
}

impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, lookup: Lookup) {
        let old_ty = *ty;
        *ty = self.renumber_regions(&old_ty);
        self.store_ty_regions(ty, lookup);
    }

    fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
        *substs = self.renumber_regions(&{*substs});
        let lookup = Lookup::Loc(location);
        for kind in *substs {
            self.store_kind_regions(kind, lookup);
        }
    }

    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
        match *rvalue {
            Rvalue::Ref(ref mut r, _, _) => {
                let old_r = *r;
                *r = self.renumber_regions(&old_r);
                let lookup = Lookup::Loc(location);
                self.store_region(r, lookup);
            }
            Rvalue::Use(..) |
            Rvalue::Repeat(..) |
            Rvalue::Len(..) |
            Rvalue::Cast(..) |
            Rvalue::BinaryOp(..) |
            Rvalue::CheckedBinaryOp(..) |
            Rvalue::UnaryOp(..) |
            Rvalue::Discriminant(..) |
            Rvalue::NullaryOp(..) |
            Rvalue::Aggregate(..) => {
                // These variants don't contain regions.
            }
        }
        self.super_rvalue(rvalue, location);
    }

    fn visit_closure_substs(&mut self,
                            substs: &mut ClosureSubsts<'tcx>,
                            location: Location) {
        *substs = self.renumber_regions(substs);
        let lookup = Lookup::Loc(location);
        for kind in substs.substs {
            self.store_kind_regions(kind, lookup);
        }
    }

    fn visit_statement(&mut self,
                       block: BasicBlock,
                       statement: &mut Statement<'tcx>,
                       location: Location) {
        if let StatementKind::EndRegion(_) = statement.kind {
            statement.kind = StatementKind::Nop;
        }
        self.super_statement(block, statement, location);
    }
}

// MIR Pass for non-lexical lifetimes
pub struct NLL;

impl MirPass for NLL {
    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          _: MirSource,
                          mir: &mut Mir<'tcx>) {
        if !tcx.sess.opts.debugging_opts.nll {
            return;
        }

        tcx.infer_ctxt().enter(|infcx| {
            // Clone mir so we can mutate it without disturbing the rest of the compiler
            let mut renumbered_mir = mir.clone();
            let mut visitor = NLLVisitor::new(infcx);
            visitor.visit_mir(&mut renumbered_mir);
            let _results = visitor.into_results();
        })
    }
}<|endoftext|>


<commit_before>use std::string::String;
use std::vec::Vec;

use byteorder::{BigEndian, WriteBytesExt};

use types::{BERT_LABEL, BertTag};

pub struct Serializer;

pub struct Deserializer {
//    data: Vec<u8>
}

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

trait Deserialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

impl Serializer {

    pub fn new() -> Serializer {
        Serializer{}
    }

    pub fn term_to_binary<T>(&self, data: T) -> Vec<u8> where Self: Serialize<T>{
        self.to_bert(data)
    }

    pub fn generate_term(&self, tag: BertTag, data: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![tag as u8];
        binary.extend(data.iter().clone());
        binary
    }

    pub fn convert_string_to_binary(&self, data: &str) -> Vec<u8> {
        let binary_string = data.as_bytes();
        let binary_length = binary_string.len() as u8;
        let mut binary = vec![0u8, binary_length];
        binary.extend(binary_string.iter().clone());
        binary
    }

    pub fn merge_atoms(&self, atom_1: Vec<u8>, atom_2: Vec<u8>) -> Vec<u8> {
        let mut binary: Vec<u8> = atom_1.clone();
        binary.extend(atom_2.iter().clone());
        binary
    }

    pub fn get_bert_atom(&self) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(BERT_LABEL);
        self.generate_term(BertTag::Atom, binary_string)
    }
}

impl Serialize<u8> for Serializer {
    fn to_bert(&self, data: u8) -> Vec<u8> {
        self.generate_term(BertTag::SmallInteger, vec![data])
    }
}

impl Serialize<i32> for Serializer {
    fn to_bert(&self, data: i32) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_i32::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::Integer, binary)
    }
}

impl Serialize<f64> for Serializer {
    fn to_bert(&self, data: f64) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_f64::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::Float, binary)
    }
}

impl Serialize<String> for Serializer {
    fn to_bert(&self, data: String) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(&data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl Serialize<bool> for Serializer {
    fn to_bert(&self, data: bool) -> Vec<u8> {
        let boolean_string = data.to_string();
        let binary_boolean = self.convert_string_to_binary(&boolean_string);

        let bert_atom = self.get_bert_atom();
        let boolean_atom = self.generate_term(BertTag::Atom, binary_boolean);

        self.merge_atoms(bert_atom, boolean_atom)
    }
}

#[cfg(test)]
mod test_serializer {
    use super::{Serializer};

    #[test]
    fn test_serialize_bool() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(true),
            vec![
                100u8, 0, 4, 98, 101, 114, 116,  // "bert" as atom
                100, 0, 4, 116, 114, 117, 101    // "true" as atom
            ]
        );

        assert_eq!(
            serializer.term_to_binary(false),
            vec![
                100u8, 0, 4, 98, 101, 114, 116,    // "bert" as atom
                100, 0, 5, 102, 97, 108, 115, 101  // "false" as atom
            ]
        );
    }
}
<commit_msg>Added tests for integer u8/i32<commit_after>use std::string::String;
use std::vec::Vec;

use byteorder::{BigEndian, WriteBytesExt};

use types::{BERT_LABEL, BertTag};

pub struct Serializer;

pub struct Deserializer {
//    data: Vec<u8>
}

pub trait Serialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

trait Deserialize<T> {
    fn to_bert(&self, data: T) -> Vec<u8>;
}

impl Serializer {

    pub fn new() -> Serializer {
        Serializer{}
    }

    pub fn term_to_binary<T>(&self, data: T) -> Vec<u8> where Self: Serialize<T> {
        let mut binary = vec![131u8];
        let serialized_data = self.to_bert(data);
        binary.extend(serialized_data.iter().clone());
        binary
    }

    pub fn generate_term(&self, tag: BertTag, data: Vec<u8>) -> Vec<u8> {
        let mut binary = vec![tag as u8];
        binary.extend(data.iter().clone());
        binary
    }

    pub fn convert_string_to_binary(&self, data: &str) -> Vec<u8> {
        let binary_string = data.as_bytes();
        let binary_length = binary_string.len() as u8;
        let mut binary = vec![0u8, binary_length];
        binary.extend(binary_string.iter().clone());
        binary
    }

    pub fn merge_atoms(&self, atom_1: Vec<u8>, atom_2: Vec<u8>) -> Vec<u8> {
        let mut binary: Vec<u8> = atom_1.clone();
        binary.extend(atom_2.iter().clone());
        binary
    }

    pub fn get_bert_atom(&self) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(BERT_LABEL);
        self.generate_term(BertTag::Atom, binary_string)
    }
}

impl Serialize<u8> for Serializer {
    fn to_bert(&self, data: u8) -> Vec<u8> {
        self.generate_term(BertTag::SmallInteger, vec![data])
    }
}

impl Serialize<i32> for Serializer {
    fn to_bert(&self, data: i32) -> Vec<u8> {
        let mut binary = vec![];
        binary.write_i32::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::Integer, binary)
    }
}

impl Serialize<f64> for Serializer {
    fn to_bert(&self, data: f64) -> Vec<u8> {
        let string_float: String = data.to_string();
        let mut binary = self.to_bert(string_float);
        //binary.write_f64::<BigEndian>(data).unwrap();
        self.generate_term(BertTag::Float, binary)
    }
}

impl Serialize<String> for Serializer {
    fn to_bert(&self, data: String) -> Vec<u8> {
        let binary_string = self.convert_string_to_binary(&data);
        self.generate_term(BertTag::String, binary_string)
    }
}

impl Serialize<bool> for Serializer {
    fn to_bert(&self, data: bool) -> Vec<u8> {
        let boolean_string = data.to_string();
        let binary_boolean = self.convert_string_to_binary(&boolean_string);

        let bert_atom = self.get_bert_atom();
        let boolean_atom = self.generate_term(BertTag::Atom, binary_boolean);

        self.merge_atoms(bert_atom, boolean_atom)
    }
}

#[cfg(test)]
mod test_serializer {
    use super::{Serializer};

    #[test]
    fn test_serialize_u8() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(1u8),
            vec![131u8, 97, 1]
        );

        assert_eq!(
            serializer.term_to_binary(255u8),
            vec![131u8, 97, 255]
        );
    }

    #[test]
    fn test_serialize_i32() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(-2147483648),
            vec![131u8, 98, 128, 0, 0, 0]
        );

        assert_eq!(
            serializer.term_to_binary(-1i32),
            vec![131u8, 98, 255, 255, 255, 255]
        );

        assert_eq!(
            serializer.term_to_binary(512i32),
            vec![131u8, 98, 0, 0, 2, 0]
        );

        assert_eq!(
            serializer.term_to_binary(2147483647),
            vec![131u8, 98, 127, 255, 255, 255]
        );
    }

    #[test]
    fn test_serialize_bool() {
        let serializer = Serializer::new();

        assert_eq!(
            serializer.term_to_binary(true),
            vec![
                131u8,
                100, 0, 4,  98, 101, 114, 116,  // "bert" as atom
                100, 0, 4, 116, 114, 117, 101   // "true" as atom
            ]
        );

        assert_eq!(
            serializer.term_to_binary(false),
            vec![
                131u8,
                100, 0, 4, 98, 101, 114, 116,      // "bert" as atom
                100, 0, 5, 102, 97, 108, 115, 101  // "false" as atom
            ]
        );
    }
}
<|endoftext|>