<commit_before>use super::*;

#[cfg(test)]
mod test {
    use super::{Request, Response, Status, EMPTY_HEADER, shrink, parse_chunk_size};

    const NUM_OF_HEADERS: usize = 4;

    #[test]
    fn test_shrink() {
        let mut arr = [EMPTY_HEADER; 16];
        {
            let slice = &mut &mut arr[..];
            assert_eq!(slice.len(), 16);
            shrink(slice, 4);
            assert_eq!(slice.len(), 4);
        }
        assert_eq!(arr.len(), 16);
    }

    macro_rules! req {
        ($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
            req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
        );
        ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
        #[test]
        fn $name() {
            let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
            let mut req = Request::new(&mut headers[..]);
            let status = req.parse($buf.as_ref());
            assert_eq!(status, $len);
            closure(req);

            fn closure($arg: Request) {
                $body
            }
        }
        )
    }

    req! {
        test_request_simple,
        b"OPTIONS / ICAP/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "OPTIONS");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 0);
            assert_eq!(req.headers.len(), 1);
        }
    }

    req! {
        test_icap_options,
        b"OPTIONS icap://example.local/service ICAP/1.0\r\nHost: example.local\r\nUser-Agent: Example-ICAP-Client-Library/2.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "OPTIONS");
            assert_eq!(req.path.unwrap(), "icap://example.local/service");
            assert_eq!(req.headers.len(), 3);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"example.local");
            assert_eq!(req.headers[1].name, "User-Agent");
            assert_eq!(req.headers[1].value, b"Example-ICAP-Client-Library/2.0");
        }
    }

    req! {
        test_basic_respmod,
        b"RESPMOD / ICAP/1.0\r\nEncapsulated: null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "RESPMOD");
        }
    }

    req! {
        test_full_respmod,
        b"RESPMOD icap://icap.example.org/satisf ICAP/1.0\r
Host: icap.example.org\r
Encapsulated: req-hdr=0, res-hdr=137, res-body=296\r
\r
GET /origin-resource HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain, image/gif\r
Accept-Encoding: gzip, compress\r
\r
HTTP/1.1 200 OK\r
Date: Mon, 10 Jan 2000 09:52:22 GMT\r
Server: Apache/1.3.6 (Unix)\r
ETag: \"63840-1ab7-378d415b\"\r
Content-Type: text/html\r
Content-Length: 51\r
\r
33\r
This is data that was returned by an origin server.\r
0\r
\r
",
        |req| {
            use SectionType::RequestHeader;
            assert_eq!(req.method.unwrap(), "RESPMOD");
            let sections = req.encapsulated_sections.unwrap();
            assert_eq!(sections[&RequestHeader], b"GET /origin-resource HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain, image/gif\r
Accept-Encoding: gzip, compress\r
\r
".to_vec());
        }
    }

    req! {
        test_request_headers_max,
        b"RESPMOD / ICAP/1.0\r\nA: A\r\nB: B\r\nC: C\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.headers.len(), NUM_OF_HEADERS);
        }
    }

    req! {
        test_request_multibyte,
        b"RESPMOD / ICAP/1.0\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "RESPMOD");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 0);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"foo.com");
            assert_eq!(req.headers[1].name, "User-Agent");
            assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
        }
    }

    req! {
        test_request_partial,
        b"RESPMOD / ICAP/1.0\r\n\r", Ok(Status::Partial),
        |_req| {}
    }

    req! {
        test_request_newlines,
        b"RESPMOD / ICAP/1.0\nHost: foo.bar\nEncapsulated:null-body=0\n\n",
        |_r| {}
    }

    req! {
        test_request_empty_lines_prefix,
        b"\r\n\r\nRESPMOD / ICAP/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "RESPMOD");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 0);
            assert_eq!(req.headers.len(), 1);
        }
    }

    req! {
        test_request_with_invalid_token_delimiter,
        b"RESPMOD\n/ ICAP/1.0\r\nHost: foo.bar\r\n\r\n",
        Err(::Error::Token),
        |_r| {}
    }

    macro_rules! res {
        ($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
            res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
        );
        ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
        #[test]
        fn $name() {
            let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
            let mut res = Response::new(&mut headers[..]);
            let status = res.parse($buf.as_ref());
            assert_eq!(status, $len);
            closure(res);

            fn closure($arg: Response) {
                $body
            }
        }
        )
    }

    res! {
        test_response_simple,
        b"ICAP/1.0 200 OK\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "OK");
        }
    }

    res! {
        test_response_newlines,
        b"ICAP/1.0 403 Forbidden\nServer: foo.bar\n\n",
        |_r| {}
    }

    res! {
        test_response_reason_missing,
        b"ICAP/1.0 200 \r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "");
        }
    }

    res! {
        test_response_reason_missing_no_space,
        b"ICAP/1.0 200\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "");
        }
    }

    res! {
        test_response_reason_with_space_and_tab,
        b"ICAP/1.0 101 Switching Protocols\t\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 101);
            assert_eq!(res.reason.unwrap(), "Switching Protocols\t");
        }
    }

    static RESPONSE_REASON_WITH_OBS_TEXT_BYTE: &'static [u8] = b"ICAP/1.0 200 X\xFFZ\r\n\r\n";
    res! {
        test_response_reason_with_obsolete_text_byte,
        RESPONSE_REASON_WITH_OBS_TEXT_BYTE,
        Err(::Error::Status),
        |_res| {}
    }

    res! {
        test_response_reason_with_nul_byte,
        b"ICAP/1.0 200 \x00\r\n\r\n",
        Err(::Error::Status),
        |_res| {}
    }

    res! {
        test_response_version_missing_space,
        b"ICAP/1.0",
        Ok(Status::Partial),
        |_res| {}
    }

    res! {
        test_response_code_missing_space,
        b"ICAP/1.0 200",
        Ok(Status::Partial),
        |_res| {}
    }

    res! {
        test_response_empty_lines_prefix_lf_only,
        b"\n\nICAP/1.0 200 OK\n\n",
        |_res| {}
    }

    #[test]
    fn test_chunk_size() {
        assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
        assert_eq!(parse_chunk_size(b"12\r\nchunk"), Ok(Status::Complete((4, 18))));
        assert_eq!(parse_chunk_size(b"3086d\r\n"), Ok(Status::Complete((7, 198765))));
        assert_eq!(parse_chunk_size(b"3735AB1;foo bar*\r\n"), Ok(Status::Complete((18, 57891505))));
        assert_eq!(parse_chunk_size(b"3735ab1 ; baz \r\n"), Ok(Status::Complete((16, 57891505))));
        assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial));
        assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial));
        assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"567xf8a\r\n"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"ffffffffffffffff\r\n"), Ok(Status::Complete((18, ::core::u64::MAX))));
        assert_eq!(parse_chunk_size(b"1ffffffffffffffff\r\n"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"Affffffffffffffff\r\n"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"fffffffffffffffff\r\n"), Err(::InvalidChunkSize));
    }

    #[cfg(feature = "std")]
    #[test]
    fn test_std_error() {
        use super::Error;
        use std::error::Error as StdError;
        let err = Error::HeaderName;
        assert_eq!(err.to_string(), err.description());
    }
}
<commit_msg>Add a test for basic request mod parsing<commit_after>use super::*;

#[cfg(test)]
mod test {
    extern crate httparse;
    use super::{Request, Response, Status, EMPTY_HEADER, shrink, parse_chunk_size, SectionType};

    const NUM_OF_HEADERS: usize = 4;

    #[test]
    fn test_shrink() {
        let mut arr = [EMPTY_HEADER; 16];
        {
            let slice = &mut &mut arr[..];
            assert_eq!(slice.len(), 16);
            shrink(slice, 4);
            assert_eq!(slice.len(), 4);
        }
        assert_eq!(arr.len(), 16);
    }

    macro_rules! req {
        ($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
            req! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
        );
        ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
        #[test]
        fn $name() {
            let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
            let mut req = Request::new(&mut headers[..]);
            let status = req.parse($buf.as_ref());
            assert_eq!(status, $len);
            closure(req);

            fn closure($arg: Request) {
                $body
            }
        }
        )
    }

    req! {
        test_request_simple,
        b"OPTIONS / ICAP/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "OPTIONS");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 0);
            assert_eq!(req.headers.len(), 1);
        }
    }

    req! {
        test_icap_options,
        b"OPTIONS icap://example.local/service ICAP/1.0\r\nHost: example.local\r\nUser-Agent: Example-ICAP-Client-Library/2.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "OPTIONS");
            assert_eq!(req.path.unwrap(), "icap://example.local/service");
            assert_eq!(req.headers.len(), 3);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"example.local");
            assert_eq!(req.headers[1].name, "User-Agent");
            assert_eq!(req.headers[1].value, b"Example-ICAP-Client-Library/2.0");
        }
    }

    req! {
        test_reqmod_basic,
        b"REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0\r
Host: icap-server.net\r
Encapsulated: req-hdr=0, null-body=170\r
\r
GET / HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain\r
Accept-Encoding: compress\r
Cookie: ff39fk3jur@4ii0e02i\r
If-None-Match: \"xyzzy\", \"r2d2xxxx\"\r
\r
",
       |req| {
           assert_eq!(req.method.unwrap(), "REQMOD");
           let encapsulated = req.encapsulated_sections.unwrap();
           assert_eq!(encapsulated.len(), 2);
           let mut headers = [httparse::EMPTY_HEADER; 16];
           let mut req = httparse::Request::new(&mut headers);
           let http_request = encapsulated.get(&SectionType::RequestHeader).unwrap();
           assert_eq!(req.parse(http_request).unwrap().is_complete(), true);
       }
    }

    req! {
        test_basic_respmod,
        b"RESPMOD / ICAP/1.0\r\nEncapsulated: null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "RESPMOD");
        }
    }

    req! {
        test_full_respmod,
        b"RESPMOD icap://icap.example.org/satisf ICAP/1.0\r
Host: icap.example.org\r
Encapsulated: req-hdr=0, res-hdr=137, res-body=296\r
\r
GET /origin-resource HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain, image/gif\r
Accept-Encoding: gzip, compress\r
\r
HTTP/1.1 200 OK\r
Date: Mon, 10 Jan 2000 09:52:22 GMT\r
Server: Apache/1.3.6 (Unix)\r
ETag: \"63840-1ab7-378d415b\"\r
Content-Type: text/html\r
Content-Length: 51\r
\r
33\r
This is data that was returned by an origin server.\r
0\r
\r
",
        |req| {
            use SectionType::RequestHeader;
            assert_eq!(req.method.unwrap(), "RESPMOD");
            let sections = req.encapsulated_sections.unwrap();
            assert_eq!(sections[&RequestHeader], b"GET /origin-resource HTTP/1.1\r
Host: www.origin-server.com\r
Accept: text/html, text/plain, image/gif\r
Accept-Encoding: gzip, compress\r
\r
".to_vec());
        }
    }

    req! {
        test_request_headers_max,
        b"RESPMOD / ICAP/1.0\r\nA: A\r\nB: B\r\nC: C\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.headers.len(), NUM_OF_HEADERS);
        }
    }

    req! {
        test_request_multibyte,
        b"RESPMOD / ICAP/1.0\r\nHost: foo.com\r\nUser-Agent: \xe3\x81\xb2\xe3/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "RESPMOD");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 0);
            assert_eq!(req.headers[0].name, "Host");
            assert_eq!(req.headers[0].value, b"foo.com");
            assert_eq!(req.headers[1].name, "User-Agent");
            assert_eq!(req.headers[1].value, b"\xe3\x81\xb2\xe3/1.0");
        }
    }

    req! {
        test_request_partial,
        b"RESPMOD / ICAP/1.0\r\n\r", Ok(Status::Partial),
        |_req| {}
    }

    req! {
        test_request_newlines,
        b"RESPMOD / ICAP/1.0\nHost: foo.bar\nEncapsulated:null-body=0\n\n",
        |_r| {}
    }

    req! {
        test_request_empty_lines_prefix,
        b"\r\n\r\nRESPMOD / ICAP/1.0\r\nEncapsulated:null-body=0\r\n\r\n",
        |req| {
            assert_eq!(req.method.unwrap(), "RESPMOD");
            assert_eq!(req.path.unwrap(), "/");
            assert_eq!(req.version.unwrap(), 0);
            assert_eq!(req.headers.len(), 1);
        }
    }

    req! {
        test_request_with_invalid_token_delimiter,
        b"RESPMOD\n/ ICAP/1.0\r\nHost: foo.bar\r\n\r\n",
        Err(::Error::Token),
        |_r| {}
    }

    macro_rules! res {
        ($name:ident, $buf:expr, |$arg:ident| $body:expr) => (
            res! {$name, $buf, Ok(Status::Complete($buf.len())), |$arg| $body }
        );
        ($name:ident, $buf:expr, $len:expr, |$arg:ident| $body:expr) => (
        #[test]
        fn $name() {
            let mut headers = [EMPTY_HEADER; NUM_OF_HEADERS];
            let mut res = Response::new(&mut headers[..]);
            let status = res.parse($buf.as_ref());
            assert_eq!(status, $len);
            closure(res);

            fn closure($arg: Response) {
                $body
            }
        }
        )
    }

    res! {
        test_response_simple,
        b"ICAP/1.0 200 OK\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "OK");
        }
    }

    res! {
        test_response_newlines,
        b"ICAP/1.0 403 Forbidden\nServer: foo.bar\n\n",
        |_r| {}
    }

    res! {
        test_response_reason_missing,
        b"ICAP/1.0 200 \r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "");
        }
    }

    res! {
        test_response_reason_missing_no_space,
        b"ICAP/1.0 200\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 200);
            assert_eq!(res.reason.unwrap(), "");
        }
    }

    res! {
        test_response_reason_with_space_and_tab,
        b"ICAP/1.0 101 Switching Protocols\t\r\n\r\n",
        |res| {
            assert_eq!(res.version.unwrap(), 0);
            assert_eq!(res.code.unwrap(), 101);
            assert_eq!(res.reason.unwrap(), "Switching Protocols\t");
        }
    }

    static RESPONSE_REASON_WITH_OBS_TEXT_BYTE: &'static [u8] = b"ICAP/1.0 200 X\xFFZ\r\n\r\n";
    res! {
        test_response_reason_with_obsolete_text_byte,
        RESPONSE_REASON_WITH_OBS_TEXT_BYTE,
        Err(::Error::Status),
        |_res| {}
    }

    res! {
        test_response_reason_with_nul_byte,
        b"ICAP/1.0 200 \x00\r\n\r\n",
        Err(::Error::Status),
        |_res| {}
    }

    res! {
        test_response_version_missing_space,
        b"ICAP/1.0",
        Ok(Status::Partial),
        |_res| {}
    }

    res! {
        test_response_code_missing_space,
        b"ICAP/1.0 200",
        Ok(Status::Partial),
        |_res| {}
    }

    res! {
        test_response_empty_lines_prefix_lf_only,
        b"\n\nICAP/1.0 200 OK\n\n",
        |_res| {}
    }

    #[test]
    fn test_chunk_size() {
        assert_eq!(parse_chunk_size(b"0\r\n"), Ok(Status::Complete((3, 0))));
        assert_eq!(parse_chunk_size(b"12\r\nchunk"), Ok(Status::Complete((4, 18))));
        assert_eq!(parse_chunk_size(b"3086d\r\n"), Ok(Status::Complete((7, 198765))));
        assert_eq!(parse_chunk_size(b"3735AB1;foo bar*\r\n"), Ok(Status::Complete((18, 57891505))));
        assert_eq!(parse_chunk_size(b"3735ab1 ; baz \r\n"), Ok(Status::Complete((16, 57891505))));
        assert_eq!(parse_chunk_size(b"77a65\r"), Ok(Status::Partial));
        assert_eq!(parse_chunk_size(b"ab"), Ok(Status::Partial));
        assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"567f8a\rfoo"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"567xf8a\r\n"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"ffffffffffffffff\r\n"), Ok(Status::Complete((18, ::core::u64::MAX))));
        assert_eq!(parse_chunk_size(b"1ffffffffffffffff\r\n"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"Affffffffffffffff\r\n"), Err(::InvalidChunkSize));
        assert_eq!(parse_chunk_size(b"fffffffffffffffff\r\n"), Err(::InvalidChunkSize));
    }

    #[cfg(feature = "std")]
    #[test]
    fn test_std_error() {
        use super::Error;
        use std::error::Error as StdError;
        let err = Error::HeaderName;
        assert_eq!(err.to_string(), err.description());
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use futures::Stream;
use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::os::unix::io::AsRawFd;
use std::pin::Pin;
use std::task::{Context, Poll};

use libc::{EWOULDBLOCK, O_NONBLOCK};

use sys_util::{self, add_fd_flags};

use cros_async::fd_executor::{self, add_read_waker};

/// Errors generated while polling for events.
#[derive(Debug)]
pub enum Error {
    /// An error occurred attempting to register a waker with the executor.
    AddingWaker(fd_executor::Error),
    /// Failure creating the event FD.
    EventFdCreate(sys_util::Error),
    /// An error occurred when reading the event FD.
    EventFdRead(sys_util::Error),
    /// An error occurred when setting the event FD non-blocking.
    SettingNonBlocking(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

impl std::error::Error for Error {}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            AddingWaker(e) => write!(
                f,
                "An error occurred attempting to register a waker with the executor: {}.",
                e
            ),
            EventFdCreate(e) => write!(f, "An error occurred when creating the event FD: {}.", e),
            EventFdRead(e) => write!(f, "An error occurred when reading the event FD: {}.", e),
            SettingNonBlocking(e) => {
                write!(f, "An error occurred setting the FD non-blocking: {}.", e)
            }
        }
    }
}

/// Asynchronous version of `sys_util::EventFd`. Provides an implementation of `futures::Stream` so
/// that events can be consumed in an async context.
///
/// # Example
///
/// ```
/// use std::convert::TryInto;
///
/// use async_core::{EventFd };
/// use futures::StreamExt;
/// use sys_util::{self};
///
/// async fn process_events() -> std::result::Result<(), Box<dyn std::error::Error>> {
///     let mut async_events: EventFd = sys_util::EventFd::new()?.try_into()?;
///     while let Some(e) = async_events.next().await {
///         // Handle event here.
///     }
///     Ok(())
/// }
/// ```
pub struct EventFd {
    inner: sys_util::EventFd,
    done: bool,
}

impl EventFd {
    pub fn new() -> Result<EventFd> {
        Self::try_from(sys_util::EventFd::new().map_err(Error::EventFdCreate)?)
    }
}

impl TryFrom<sys_util::EventFd> for EventFd {
    type Error = crate::eventfd::Error;

    fn try_from(eventfd: sys_util::EventFd) -> Result<EventFd> {
        let fd = eventfd.as_raw_fd();
        add_fd_flags(fd, O_NONBLOCK).map_err(Error::SettingNonBlocking)?;
        Ok(EventFd {
            inner: eventfd,
            done: false,
        })
    }
}

impl Stream for EventFd {
    type Item = Result<u64>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        if self.done {
            return Poll::Ready(None);
        }

        let res = self
            .inner
            .read()
            .map(|v| Poll::Ready(Some(Ok(v))))
            .or_else(|e| {
                if e.errno() == EWOULDBLOCK {
                    add_read_waker(self.inner.as_raw_fd(), cx.waker().clone())
                        .map(|_token| Poll::Pending)
                        .map_err(Error::AddingWaker)
                } else {
                    Err(Error::EventFdRead(e))
                }
            });

        match res {
            Ok(v) => v,
            Err(e) => {
                self.done = true;
                Poll::Ready(Some(Err(e)))
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cros_async::{select2, SelectResult};
    use futures::future::pending;
    use futures::pin_mut;
    use futures::stream::StreamExt;

    #[test]
    fn eventfd_write_read() {
        let evt = EventFd::new().unwrap();
        async fn read_one(mut evt: EventFd) -> u64 {
            if let Some(Ok(e)) = evt.next().await {
                e
            } else {
                66
            }
        }
        async fn write_pend(evt: sys_util::EventFd) {
            evt.write(55).unwrap();
            let () = pending().await;
        }
        let write_evt = evt.inner.try_clone().unwrap();

        let r = read_one(evt);
        pin_mut!(r);
        let w = write_pend(write_evt);
        pin_mut!(w);

        if let Ok((SelectResult::Finished(read_res), SelectResult::Pending(_pend_fut))) =
            select2(r, w)
        {
            assert_eq!(read_res, 55);
        } else {
            panic!("wrong futures returned from select2");
        }
    }
}
<commit_msg>async_core: eventfd: implement a future for the next value<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::convert::TryFrom;
use std::fmt::{self, Display};
use std::future::Future;
use std::os::unix::io::AsRawFd;
use std::pin::Pin;
use std::task::{Context, Poll};

use libc::{EWOULDBLOCK, O_NONBLOCK};

use cros_async::fd_executor::{self, add_read_waker, cancel_waker, WakerToken};
use sys_util::{self, add_fd_flags};

/// Errors generated while polling for events.
#[derive(Debug)]
pub enum Error {
    /// An error occurred attempting to register a waker with the executor.
    AddingWaker(fd_executor::Error),
    /// Failure creating the event FD.
    EventFdCreate(sys_util::Error),
    /// An error occurred when reading the event FD.
    EventFdRead(sys_util::Error),
    /// An error occurred when setting the event FD non-blocking.
    SettingNonBlocking(sys_util::Error),
}
pub type Result<T> = std::result::Result<T, Error>;

impl std::error::Error for Error {}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            AddingWaker(e) => write!(
                f,
                "An error occurred attempting to register a waker with the executor: {}.",
                e
            ),
            EventFdCreate(e) => write!(f, "An error occurred when creating the event FD: {}.", e),
            EventFdRead(e) => write!(f, "An error occurred when reading the event FD: {}.", e),
            SettingNonBlocking(e) => {
                write!(f, "An error occurred setting the FD non-blocking: {}.", e)
            }
        }
    }
}

/// Asynchronous version of `sys_util::EventFd`. Provides asynchronous values that complete when the
/// next event can be read from the eventfd.
///
/// # Example
///
/// ```
/// use std::convert::TryInto;
///
/// use async_core::{EventFd};
/// use sys_util::{self};
///
/// async fn process_events() -> std::result::Result<(), Box<dyn std::error::Error>> {
///     let mut async_events: EventFd = sys_util::EventFd::new()?.try_into()?;
///     while let Ok(e) = async_events.read_next().await {
///         // Handle event here.
///     }
///     Ok(())
/// }
/// ```
pub struct EventFd {
    inner: sys_util::EventFd,
}

impl EventFd {
    pub fn new() -> Result<EventFd> {
        Self::try_from(sys_util::EventFd::new().map_err(Error::EventFdCreate)?)
    }

    /// Asynchronously read the next value from the eventfd.
    /// Returns a Future that can be `awaited` for the next value.
    ///
    /// # Example
    ///
    /// ```
    /// use async_core::EventFd;
    /// async fn print_events(mut event_fd: EventFd) {
    ///     loop {
    ///         match event_fd.read_next().await {
    ///             Ok(e) => println!("Got event: {}", e),
    ///             Err(e) => break,
    ///         }
    ///     }
    /// }
    /// ```
    pub fn read_next(&mut self) -> NextValFuture {
        NextValFuture::new(self)
    }
}

impl TryFrom<sys_util::EventFd> for EventFd {
    type Error = crate::eventfd::Error;

    fn try_from(eventfd: sys_util::EventFd) -> Result<EventFd> {
        let fd = eventfd.as_raw_fd();
        add_fd_flags(fd, O_NONBLOCK).map_err(Error::SettingNonBlocking)?;
        Ok(EventFd { inner: eventfd })
    }
}

/// A Future that yields the next value from the eventfd when it is ready.
pub struct NextValFuture<'a> {
    eventfd: &'a mut EventFd,
    waker_token: Option<WakerToken>,
}

impl<'a> NextValFuture<'a> {
    fn new(eventfd: &'a mut EventFd) -> NextValFuture<'a> {
        NextValFuture {
            eventfd,
            waker_token: None,
        }
    }
}

impl<'a> Future for NextValFuture<'a> {
    type Output = Result<u64>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        if let Some(token) = self.waker_token.take() {
            let _ = cancel_waker(token);
        }

        match self.eventfd.inner.read() {
            Ok(v) => Poll::Ready(Ok(v)),
            Err(e) => {
                if e.errno() == EWOULDBLOCK {
                    match add_read_waker(self.eventfd.inner.as_raw_fd(), cx.waker().clone()) {
                        Ok(token) => {
                            self.waker_token = Some(token);
                            Poll::Pending
                        }
                        Err(e) => Poll::Ready(Err(Error::AddingWaker(e))),
                    }
                } else {
                    Poll::Ready(Err(Error::EventFdRead(e)))
                }
            }
        }
    }
}

impl<'a> Drop for NextValFuture<'a> {
    fn drop(&mut self) {
        if let Some(token) = self.waker_token.take() {
            let _ = cancel_waker(token);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use cros_async::{select2, SelectResult};
    use futures::future::pending;
    use futures::pin_mut;

    #[test]
    fn eventfd_write_read() {
        let evt = EventFd::new().unwrap();
        async fn read_one(mut evt: EventFd) -> u64 {
            if let Ok(e) = evt.read_next().await {
                e
            } else {
                66
            }
        }
        async fn write_pend(evt: sys_util::EventFd) {
            evt.write(55).unwrap();
            let () = pending().await;
        }
        let write_evt = evt.inner.try_clone().unwrap();

        let r = read_one(evt);
        pin_mut!(r);
        let w = write_pend(write_evt);
        pin_mut!(w);

        if let Ok((SelectResult::Finished(read_res), SelectResult::Pending(_pend_fut))) =
            select2(r, w)
        {
            assert_eq!(read_res, 55);
        } else {
            panic!("wrong futures returned from select2");
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]

extern crate compiletest_rs as compiletest;

use api::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use std::path::PathBuf;

fn quick_sort<T:PartialOrd+Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo),
         || quick_sort(hi));
}

fn partition<T:PartialOrd+Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6*1024).map(|_| rng.next_u32()).collect();

    let result = initialize(Configuration::new());

    match result {
        Ok(_) => {
            quick_sort(&mut data);

            let mut sorted_data = data.clone();
            sorted_data.sort();

            assert_eq!(data, sorted_data);
        },
        Err(e) => panic!("expected InitOk, but got {:?}", e),
    }
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12*1024).map(|_| rng.next_u32()).collect();

    let result = ThreadPool::new(Configuration::new());

    match result {
        Ok(pool) => {
            pool.install(|| {
                quick_sort(&mut data);
            });

            let mut sorted_data = data.clone();
            sorted_data.sort();

            assert_eq!(data, sorted_data);
        },
        Err(_) => panic!("expected Ok() but got Err()")
    }
}

#[test]
fn error_in_pool() {
    let result = ThreadPool::new(Configuration::new().set_num_threads(0));

    match result {
        Ok(_) => panic!("expected Err(), but got Ok()"),
        Err(error) => assert_eq!(error, InitError::NumberOfThreadsZero)
    }
}

#[test]
fn negative_tests_compile_fail() {
    let mode = "compile-fail";
    let mut config = compiletest::default_config();
    let cfg_mode = mode.parse().ok().expect("Invalid mode");

    config.mode = cfg_mode;
    config.src_base = PathBuf::from("neg-tests-compile");
    config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());

    compiletest::run_tests(&config);
}

#[test]
fn positive_test_run_pass() {
    let mode = "run-pass";
    let mut config = compiletest::default_config();
    let cfg_mode = mode.parse().ok().expect("Invalid mode");

    config.mode = cfg_mode;
    config.src_base = PathBuf::from("pos-tests-run");
    config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());

    compiletest::run_tests(&config);
}
<commit_msg>fix #39 add coercion to Error test case<commit_after>#![cfg(test)]

extern crate compiletest_rs as compiletest;

use api::*;
use rand::{Rng, SeedableRng, XorShiftRng};
use std::path::PathBuf;
use std::error::Error;

fn quick_sort<T:PartialOrd+Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }

    let mid = partition(v);
    let (lo, hi) = v.split_at_mut(mid);
    join(|| quick_sort(lo),
         || quick_sort(hi));
}

fn partition<T:PartialOrd+Send>(v: &mut [T]) -> usize {
    let pivot = v.len() - 1;
    let mut i = 0;
    for j in 0..pivot {
        if v[j] <= v[pivot] {
            v.swap(i, j);
            i += 1;
        }
    }
    v.swap(i, pivot);
    i
}

#[test]
fn sort() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..6*1024).map(|_| rng.next_u32()).collect();

    let result = initialize(Configuration::new());

    match result {
        Ok(_) => {
            quick_sort(&mut data);

            let mut sorted_data = data.clone();
            sorted_data.sort();

            assert_eq!(data, sorted_data);
        },
        Err(e) => panic!("expected InitOk, but got {:?}", e),
    }
}

#[test]
fn sort_in_pool() {
    let mut rng = XorShiftRng::from_seed([0, 1, 2, 3]);
    let mut data: Vec<_> = (0..12*1024).map(|_| rng.next_u32()).collect();

    let result = ThreadPool::new(Configuration::new());

    match result {
        Ok(pool) => {
            pool.install(|| {
                quick_sort(&mut data);
            });

            let mut sorted_data = data.clone();
            sorted_data.sort();

            assert_eq!(data, sorted_data);
        },
        Err(_) => panic!("expected Ok() but got Err()")
    }
}

#[test]
fn error_in_pool() {
    let result = ThreadPool::new(Configuration::new().set_num_threads(0));

    match result {
        Ok(_) => panic!("expected Err(), but got Ok()"),
        Err(error) => assert_eq!(error, InitError::NumberOfThreadsZero)
    }
}

#[test]
fn negative_tests_compile_fail() {
    let mode = "compile-fail";
    let mut config = compiletest::default_config();
    let cfg_mode = mode.parse().ok().expect("Invalid mode");

    config.mode = cfg_mode;
    config.src_base = PathBuf::from("neg-tests-compile");
    config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());

    compiletest::run_tests(&config);
}

#[test]
fn positive_test_run_pass() {
    let mode = "run-pass";
    let mut config = compiletest::default_config();
    let cfg_mode = mode.parse().ok().expect("Invalid mode");

    config.mode = cfg_mode;
    config.src_base = PathBuf::from("pos-tests-run");
    config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());

    compiletest::run_tests(&config);
}

#[test]
fn coerce_to_box_error() {
     // check that coercion succeeds
    let _: Box<Error> = From::from(InitError::NumberOfThreadsZero);
}
<|endoftext|>


<commit_before>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

//! Module containing TaskPriority types and trait impls

/// Enum for the priorities taskwarrior supports.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TaskPriority {
    /// Low prio for a Task
    Low,

    /// Medium prio for a Task
    Medium,

    /// High prio for a Task
    High,
}

<commit_msg>Rename priorities<commit_after>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

//! Module containing TaskPriority types and trait impls

/// Enum for the priorities taskwarrior supports.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TaskPriority {
    /// Low prio for a Task
    #[serde(rename = "L")]
    Low,

    /// Medium prio for a Task
    #[serde(rename = "M")]
    Medium,

    /// High prio for a Task
    #[serde(rename = "H")]
    High,
}

<|endoftext|>


<commit_before>use std::net::TcpStream;
use openssl::ssl::{SslContext, SslStream};
use std::io::{Error, ErrorKind, Read, Result, Write};
use regex::Regex;

enum IMAPStreamTypes {
	Basic(TcpStream),
	Ssl(SslStream<TcpStream>)
}

pub struct IMAPStream {
	stream: IMAPStreamTypes,
	pub host: String,
	pub port: u16,
	tag: u32,
	tag_prefix: &'static str
}

pub struct IMAPMailbox {
	pub flags: String,
	pub exists: u32,
	pub recent: u32,
	pub unseen: Option<u32>,
	pub permanent_flags: Option<String>,
	pub uid_next: Option<u32>,
	pub uid_validity: Option<u32>
}

impl IMAPStream {

	pub fn connect<S: Into<String>>(host: S, port: u16, ssl_context: Option<SslContext>) -> Result<IMAPStream> {
                let host_string = host.into();
		let connect_string = format!("{}:{}", host_string, port);
		let tcp_stream = TcpStream::connect(&*connect_string).unwrap();
		let mut socket = match ssl_context {
			Some(context) => IMAPStream { stream: IMAPStreamTypes::Ssl(SslStream::new(&context, tcp_stream).unwrap()), host: host_string, port: port, tag: 1, tag_prefix: "a"},
			None => IMAPStream { stream: IMAPStreamTypes::Basic(tcp_stream), host: host_string, port: port, tag: 1, tag_prefix: "a"},
		};

		match socket.read_greeting() {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read greet response"))
		}

		Ok(socket)
	}

	//LOGIN
	pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
		self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
	}

	//SELECT
	pub fn select(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("SELECT {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_select_or_examine(lines: Vec<String>) -> Result<IMAPMailbox> {
		let exists_regex = match Regex::new(r"^\* (\d+) EXISTS\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let recent_regex = match Regex::new(r"^\* (\d+) RECENT\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let flags_regex = match Regex::new(r"^\* FLAGS (.+)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let unseen_regex = match Regex::new(r"^OK \[UNSEEN (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_validity_regex = match Regex::new(r"^OK \[UIDVALIDITY (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_next_regex = match Regex::new(r"^OK \[UIDNEXT (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let permanent_flags_regex = match Regex::new(r"^OK \[PERMANENTFLAGS (.+)\]\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		let mut mailbox = IMAPMailbox{
			flags: "".to_string(),
			exists: 0,
			recent: 0,
			unseen: None,
			permanent_flags: None,
			uid_next: None,
			uid_validity: None
		};

		for line in lines.iter() {
			if exists_regex.is_match(line) {
				let cap = exists_regex.captures(line).unwrap();
				mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if recent_regex.is_match(line) {
				let cap = recent_regex.captures(line).unwrap();
				mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if flags_regex.is_match(line) {
				let cap = flags_regex.captures(line).unwrap();
				mailbox.flags = cap.at(1).unwrap().to_string();
			} else if unseen_regex.is_match(line) {
				let cap = unseen_regex.captures(line).unwrap();
				mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_validity_regex.is_match(line) {
				let cap = uid_validity_regex.captures(line).unwrap();
				mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_next_regex.is_match(line) {
				let cap = uid_next_regex.captures(line).unwrap();
				mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if permanent_flags_regex.is_match(line) {
				let cap = permanent_flags_regex.captures(line).unwrap();
				mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
			}
		}

		return Ok(mailbox);
	}

	//EXAMINE
	pub fn examine(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("EXAMINE {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	//FETCH
	pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
		self.run_command(&format!("FETCH {} {}", sequence_set, query).to_string())
	}

	//NOOP
	pub fn noop(&mut self) -> Result<()> {
		self.run_command_and_check_ok("NOOP")
	}

	//LOGOUT
	pub fn logout(&mut self) -> Result<()> {
		self.run_command_and_check_ok("LOGOUT")
	}

	//CREATE
	pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("CREATE {}", mailbox_name).to_string())
	}

	//DELETE
	pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("DELETE {}", mailbox_name).to_string())
	}

	//RENAME
	pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
	}

	//SUBSCRIBE
	pub fn subscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
	}

	//UNSUBSCRIBE
	pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
	}

	//CAPABILITY
	pub fn capability(&mut self) -> Result<Vec<String>> {
		match self.run_command(&format!("CAPABILITY").to_string()) {
			Ok(lines) => IMAPStream::parse_capability(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
		let capability_regex = match Regex::new(r"^\* CAPABILITY (.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		for line in lines.iter() {
			if capability_regex.is_match(line) {
				let cap = capability_regex.captures(line).unwrap();
				let capabilities_str = cap.at(1).unwrap();
				return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
			}
		}

		Err(Error::new(ErrorKind::Other, "Error parsing capabilities response"))
	}

	//COPY
	pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
	}

	fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
		match self.run_command(command) {
			Ok(lines) => IMAPStream::parse_response_ok(lines),
			Err(e) => Err(e)
		}
	}

	fn run_command(&mut self, untagged_command: &str) -> Result<Vec<String>> {
		let command = self.create_command(untagged_command.to_string());

		match self.write_str(&*command) {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to write")),
		};

		let ret = match self.read_response() {
			Ok(lines) => Ok(lines),
			Err(_) => Err(Error::new(ErrorKind::Other, "Failed to read")),
		};

		self.tag += 1;

		return ret;
	}

	fn parse_response_ok(lines: Vec<String>) -> Result<()> {
		let ok_regex = match Regex::new(r"^([a-zA-Z0-9]+) ([a-zA-Z0-9]+)(.*)") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};
		let last_line = lines.last().unwrap();

		for cap in ok_regex.captures_iter(last_line) {
			let response_type = cap.at(2).unwrap_or("");
			if response_type == "OK" {
				return Ok(());
			}
		}

		return Err(Error::new(ErrorKind::Other, format!("Invalid Response: {}", last_line).to_string()));
	}

	fn write_str(&mut self, s: &str) -> Result<()> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
			IMAPStreamTypes::Basic(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
		}
	}

	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.read(buf),
			IMAPStreamTypes::Basic(ref mut stream) => stream.read(buf),
		}
	}

	fn read_response(&mut self) -> Result<Vec<String>> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut found_tag_line = false;
		let start_str = format!("a{} ", self.tag);
		let mut lines: Vec<String> = Vec::new();

		while !found_tag_line {
			let mut line_buffer: Vec<u8> = Vec::new();
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
					let byte_buffer: &mut [u8] = &mut [0];
					match self.read(byte_buffer) {
						Ok(_) => {},
						Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
					}
					line_buffer.push(byte_buffer[0]);
			}

			let line = String::from_utf8(line_buffer).unwrap();

			lines.push(line.clone());

			if (&*line).starts_with(&*start_str) {
				found_tag_line = true;
			}
		}

		Ok(lines)
	}

	fn read_greeting(&mut self) -> Result<()> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;

		let mut line_buffer: Vec<u8> = Vec::new();
		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		Ok(())
	}

	fn create_command(&mut self, command: String) -> String {
		let command = format!("{}{} {}\r\n", self.tag_prefix, self.tag, command);
		return command;
	}
}
<commit_msg>Expose run_command<commit_after>use std::net::TcpStream;
use openssl::ssl::{SslContext, SslStream};
use std::io::{Error, ErrorKind, Read, Result, Write};
use regex::Regex;

enum IMAPStreamTypes {
	Basic(TcpStream),
	Ssl(SslStream<TcpStream>)
}

pub struct IMAPStream {
	stream: IMAPStreamTypes,
	pub host: String,
	pub port: u16,
	tag: u32,
	tag_prefix: &'static str
}

pub struct IMAPMailbox {
	pub flags: String,
	pub exists: u32,
	pub recent: u32,
	pub unseen: Option<u32>,
	pub permanent_flags: Option<String>,
	pub uid_next: Option<u32>,
	pub uid_validity: Option<u32>
}

impl IMAPStream {

	pub fn connect<S: Into<String>>(host: S, port: u16, ssl_context: Option<SslContext>) -> Result<IMAPStream> {
                let host_string = host.into();
		let connect_string = format!("{}:{}", host_string, port);
		let tcp_stream = TcpStream::connect(&*connect_string).unwrap();
		let mut socket = match ssl_context {
			Some(context) => IMAPStream { stream: IMAPStreamTypes::Ssl(SslStream::new(&context, tcp_stream).unwrap()), host: host_string, port: port, tag: 1, tag_prefix: "a"},
			None => IMAPStream { stream: IMAPStreamTypes::Basic(tcp_stream), host: host_string, port: port, tag: 1, tag_prefix: "a"},
		};

		match socket.read_greeting() {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read greet response"))
		}

		Ok(socket)
	}

	//LOGIN
	pub fn login(&mut self, username: & str, password: & str) -> Result<()> {
		self.run_command_and_check_ok(&format!("LOGIN {} {}", username, password).to_string())
	}

	//SELECT
	pub fn select(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("SELECT {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_select_or_examine(lines: Vec<String>) -> Result<IMAPMailbox> {
		let exists_regex = match Regex::new(r"^\* (\d+) EXISTS\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let recent_regex = match Regex::new(r"^\* (\d+) RECENT\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let flags_regex = match Regex::new(r"^\* FLAGS (.+)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let unseen_regex = match Regex::new(r"^OK \[UNSEEN (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_validity_regex = match Regex::new(r"^OK \[UIDVALIDITY (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let uid_next_regex = match Regex::new(r"^OK \[UIDNEXT (\d+)\](.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		let permanent_flags_regex = match Regex::new(r"^OK \[PERMANENTFLAGS (.+)\]\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		let mut mailbox = IMAPMailbox{
			flags: "".to_string(),
			exists: 0,
			recent: 0,
			unseen: None,
			permanent_flags: None,
			uid_next: None,
			uid_validity: None
		};

		for line in lines.iter() {
			if exists_regex.is_match(line) {
				let cap = exists_regex.captures(line).unwrap();
				mailbox.exists = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if recent_regex.is_match(line) {
				let cap = recent_regex.captures(line).unwrap();
				mailbox.recent = cap.at(1).unwrap().parse::<u32>().unwrap();
			} else if flags_regex.is_match(line) {
				let cap = flags_regex.captures(line).unwrap();
				mailbox.flags = cap.at(1).unwrap().to_string();
			} else if unseen_regex.is_match(line) {
				let cap = unseen_regex.captures(line).unwrap();
				mailbox.unseen = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_validity_regex.is_match(line) {
				let cap = uid_validity_regex.captures(line).unwrap();
				mailbox.uid_validity = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if uid_next_regex.is_match(line) {
				let cap = uid_next_regex.captures(line).unwrap();
				mailbox.uid_next = Some(cap.at(1).unwrap().parse::<u32>().unwrap());
			} else if permanent_flags_regex.is_match(line) {
				let cap = permanent_flags_regex.captures(line).unwrap();
				mailbox.permanent_flags = Some(cap.at(1).unwrap().to_string());
			}
		}

		return Ok(mailbox);
	}

	//EXAMINE
	pub fn examine(&mut self, mailbox_name: &str) -> Result<IMAPMailbox> {
		match self.run_command(&format!("EXAMINE {}", mailbox_name).to_string()) {
			Ok(lines) => IMAPStream::parse_select_or_examine(lines),
			Err(e) => Err(e)
		}
	}

	//FETCH
	pub fn fetch(&mut self, sequence_set: &str, query: &str) -> Result<Vec<String>> {
		self.run_command(&format!("FETCH {} {}", sequence_set, query).to_string())
	}

	//NOOP
	pub fn noop(&mut self) -> Result<()> {
		self.run_command_and_check_ok("NOOP")
	}

	//LOGOUT
	pub fn logout(&mut self) -> Result<()> {
		self.run_command_and_check_ok("LOGOUT")
	}

	//CREATE
	pub fn create(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("CREATE {}", mailbox_name).to_string())
	}

	//DELETE
	pub fn delete(&mut self, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("DELETE {}", mailbox_name).to_string())
	}

	//RENAME
	pub fn rename(&mut self, current_mailbox_name: &str, new_mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("RENAME {} {}", current_mailbox_name, new_mailbox_name).to_string())
	}

	//SUBSCRIBE
	pub fn subscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("SUBSCRIBE {}", mailbox).to_string())
	}

	//UNSUBSCRIBE
	pub fn unsubscribe(&mut self, mailbox: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("UNSUBSCRIBE {}", mailbox).to_string())
	}

	//CAPABILITY
	pub fn capability(&mut self) -> Result<Vec<String>> {
		match self.run_command(&format!("CAPABILITY").to_string()) {
			Ok(lines) => IMAPStream::parse_capability(lines),
			Err(e) => Err(e)
		}
	}

	fn parse_capability(lines: Vec<String>) -> Result<Vec<String>> {
		let capability_regex = match Regex::new(r"^\* CAPABILITY (.*)\r\n") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};

		//Check Ok
		match IMAPStream::parse_response_ok(lines.clone()) {
			Ok(_) => (),
			Err(e) => return Err(e)
		};

		for line in lines.iter() {
			if capability_regex.is_match(line) {
				let cap = capability_regex.captures(line).unwrap();
				let capabilities_str = cap.at(1).unwrap();
				return Ok(capabilities_str.split(' ').map(|x| x.to_string()).collect());
			}
		}

		Err(Error::new(ErrorKind::Other, "Error parsing capabilities response"))
	}

	//COPY
	pub fn copy(&mut self, sequence_set: &str, mailbox_name: &str) -> Result<()> {
		self.run_command_and_check_ok(&format!("COPY {} {}", sequence_set, mailbox_name).to_string())
	}

	pub fn run_command_and_check_ok(&mut self, command: &str) -> Result<()> {
		match self.run_command(command) {
			Ok(lines) => IMAPStream::parse_response_ok(lines),
			Err(e) => Err(e)
		}
	}

	pub fn run_command(&mut self, untagged_command: &str) -> Result<Vec<String>> {
		let command = self.create_command(untagged_command.to_string());

		match self.write_str(&*command) {
			Ok(_) => (),
			Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to write")),
		};

		let ret = match self.read_response() {
			Ok(lines) => Ok(lines),
			Err(_) => Err(Error::new(ErrorKind::Other, "Failed to read")),
		};

		self.tag += 1;

		return ret;
	}

	fn parse_response_ok(lines: Vec<String>) -> Result<()> {
		let ok_regex = match Regex::new(r"^([a-zA-Z0-9]+) ([a-zA-Z0-9]+)(.*)") {
    		Ok(re) => re,
    		Err(err) => panic!("{}", err),
		};
		let last_line = lines.last().unwrap();

		for cap in ok_regex.captures_iter(last_line) {
			let response_type = cap.at(2).unwrap_or("");
			if response_type == "OK" {
				return Ok(());
			}
		}

		return Err(Error::new(ErrorKind::Other, format!("Invalid Response: {}", last_line).to_string()));
	}

	fn write_str(&mut self, s: &str) -> Result<()> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
			IMAPStreamTypes::Basic(ref mut stream) => stream.write_fmt(format_args!("{}", s)),
		}
	}

	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		match self.stream {
			IMAPStreamTypes::Ssl(ref mut stream) => stream.read(buf),
			IMAPStreamTypes::Basic(ref mut stream) => stream.read(buf),
		}
	}

	fn read_response(&mut self) -> Result<Vec<String>> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;
		let mut found_tag_line = false;
		let start_str = format!("a{} ", self.tag);
		let mut lines: Vec<String> = Vec::new();

		while !found_tag_line {
			let mut line_buffer: Vec<u8> = Vec::new();
			while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
					let byte_buffer: &mut [u8] = &mut [0];
					match self.read(byte_buffer) {
						Ok(_) => {},
						Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
					}
					line_buffer.push(byte_buffer[0]);
			}

			let line = String::from_utf8(line_buffer).unwrap();

			lines.push(line.clone());

			if (&*line).starts_with(&*start_str) {
				found_tag_line = true;
			}
		}

		Ok(lines)
	}

	fn read_greeting(&mut self) -> Result<()> {
		//Carriage return
		let cr = 0x0d;
		//Line Feed
		let lf = 0x0a;

		let mut line_buffer: Vec<u8> = Vec::new();
		while line_buffer.len() < 2 || (line_buffer[line_buffer.len()-1] != lf && line_buffer[line_buffer.len()-2] != cr) {
				let byte_buffer: &mut [u8] = &mut [0];
				match self.read(byte_buffer) {
					Ok(_) => {},
					Err(_) => return Err(Error::new(ErrorKind::Other, "Failed to read the response")),
				}
				line_buffer.push(byte_buffer[0]);
		}

		Ok(())
	}

	fn create_command(&mut self, command: String) -> String {
		let command = format!("{}{} {}\r\n", self.tag_prefix, self.tag, command);
		return command;
	}
}
<|endoftext|>


<commit_before>use std::net::{SocketAddr, ToSocketAddrs};
use json::{ToJsonnable, FromJsonnable};
use serde::de::{Error, Type};
use serde_json::value::Value;
use serde_json::error::Error as JsonError;
use serde_json::builder::ObjectBuilder;

#[derive(Debug, Clone, Eq)]
pub struct ChatUser {
	/// User's desired name
	pub name: String,
	poster: Option<SocketAddr>,
}

impl ChatUser {
	//TODO: look up the addr from name/vice versa, maybe?
	/// Creates a user defined by the supplied arguments
	pub fn get<Addr: ToSocketAddrs>(name: String, poster: Addr) -> ChatUser {
		ChatUser{
			name: name,
			poster: Self::socket_addr_to_option(poster),
		}
	}

	/// Creates a named, IP-less user.
	/// Used by the client, as it doesn't know its IP, which is filled in server-side using [`fill_ip()`](#method.fill_ip).
	pub fn me(name: String) -> ChatUser {
		ChatUser{
			name: name,
			poster: None,
		}
	}

	/// Server-side function to fill in user's IP, see [`me()`](#method.me).
	pub fn fill_ip<Addr: ToSocketAddrs>(&mut self, poster: Addr) {
		self.poster = Self::socket_addr_to_option(poster);
	}

	fn socket_addr_to_option<Addr: ToSocketAddrs>(poster: Addr) -> Option<SocketAddr> {
		match poster.to_socket_addrs() {
			Ok(mut itr) =>
				match itr.next() {
					Some(addr) => Some(addr),
					None => None,
				},
			Err(_) => None,
		}
	}
}

impl PartialEq for ChatUser {
	/// Only poster-wise comparison, names might change
	fn eq(&self, other: &ChatUser) -> bool {
		self.poster == other.poster
	}
}

impl FromJsonnable for ChatUser {
	fn from_json(json: Value) -> Result<ChatUser, JsonError> {
		match json {
			Value::Object(map) => {
				let name =
					match map.get("name") {
						Some(name) =>
							match name {
								&Value::String(ref name) => name,
								_                        => return Err(JsonError::type_mismatch(Type::String)),
							},
						None => return Err(JsonError::missing_field("Missing \"name\"")),
					};
				let poster =
					match map.get("poster") {
						Some(poster) =>
							match poster {
								&Value::String(ref poster) => poster,
								_                          => return Err(JsonError::type_mismatch(Type::String)),
							},
						None => return Err(JsonError::missing_field("Missing \"poster\"")),
					};

				Ok(ChatUser::get(name.clone(), &poster[..]))
			},
			Value::String(name) => Ok(ChatUser::me(name)),
			_                   => Err(JsonError::type_mismatch(Type::Struct)),
		}
	}
}

impl ToJsonnable for ChatUser {
	fn to_json(&self) -> Value {
		match self.poster {
			Some(ref ip) =>
				ObjectBuilder::new().insert("name", &self.name)
			                      .insert("poster", ip.to_string())
			                      .unwrap(),
			None => Value::String(self.name.clone()),
		}
	}
}
<commit_msg>Compare users name-wise<commit_after>use std::net::{SocketAddr, ToSocketAddrs};
use json::{ToJsonnable, FromJsonnable};
use serde::de::{Error, Type};
use serde_json::value::Value;
use serde_json::error::Error as JsonError;
use serde_json::builder::ObjectBuilder;

#[derive(Debug, Clone, Eq)]
pub struct ChatUser {
	/// User's desired name
	pub name: String,
	poster: Option<SocketAddr>,
}

impl ChatUser {
	/// Creates a user defined by the supplied arguments
	pub fn get<Addr: ToSocketAddrs>(name: String, poster: Addr) -> ChatUser {
		ChatUser{
			name: name,
			poster: Self::socket_addr_to_option(poster),
		}
	}

	/// Creates a named, IP-less user.
	/// Used by the client, as it doesn't know its IP, which is filled in server-side using [`fill_ip()`](#method.fill_ip).
	pub fn me(name: String) -> ChatUser {
		ChatUser{
			name: name,
			poster: None,
		}
	}

	/// Server-side function to fill in user's IP, see [`me()`](#method.me).
	pub fn fill_ip<Addr: ToSocketAddrs>(&mut self, poster: Addr) {
		self.poster = Self::socket_addr_to_option(poster);
	}

	fn socket_addr_to_option<Addr: ToSocketAddrs>(poster: Addr) -> Option<SocketAddr> {
		match poster.to_socket_addrs() {
			Ok(mut itr) =>
				match itr.next() {
					Some(addr) => Some(addr),
					None => None,
				},
			Err(_) => None,
		}
	}
}

impl PartialEq for ChatUser {
	/// Name-wise comparison for convenience
	fn eq(&self, other: &ChatUser) -> bool {
		self.name == other.name
	}
}

impl FromJsonnable for ChatUser {
	fn from_json(json: Value) -> Result<ChatUser, JsonError> {
		match json {
			Value::Object(map) => {
				let name =
					match map.get("name") {
						Some(name) =>
							match name {
								&Value::String(ref name) => name,
								_                        => return Err(JsonError::type_mismatch(Type::String)),
							},
						None => return Err(JsonError::missing_field("Missing \"name\"")),
					};
				let poster =
					match map.get("poster") {
						Some(poster) =>
							match poster {
								&Value::String(ref poster) => poster,
								_                          => return Err(JsonError::type_mismatch(Type::String)),
							},
						None => return Err(JsonError::missing_field("Missing \"poster\"")),
					};

				Ok(ChatUser::get(name.clone(), &poster[..]))
			},
			Value::String(name) => Ok(ChatUser::me(name)),
			_                   => Err(JsonError::type_mismatch(Type::Struct)),
		}
	}
}

impl ToJsonnable for ChatUser {
	fn to_json(&self) -> Value {
		match self.poster {
			Some(ref ip) =>
				ObjectBuilder::new().insert("name", &self.name)
			                      .insert("poster", ip.to_string())
			                      .unwrap(),
			None => Value::String(self.name.clone()),
		}
	}
}
<|endoftext|>


<commit_before>//! An extension trait that provides the ability to strip IRC colors from a string
use std::borrow::Cow;

#[derive(PartialEq)]
enum ParserState {
    Text,
    ColorCode,
    Foreground1,
    Foreground2,
    Comma,
    Background1,
}
struct Parser {
    state: ParserState,
}

/// An extension trait giving strings a function to strip IRC colors
pub trait FormattedStringExt {

    /// Returns true if the string contains color, bold, underline or italics
    fn is_formatted(&self) -> bool;

    /// Returns the string with all color, bold, underline and italics stripped
    fn strip_formatting(&self) -> Cow<str>;

}

impl FormattedStringExt for str {
    fn is_formatted(&self) -> bool {
        self.contains('\x02') || // bold
            self.contains('\x1F') || // underline
            self.contains('\x16') || // reverse
            self.contains('\x0F') || // normal
            self.contains('\x03') // color
    }

    fn strip_formatting(&self) -> Cow<str> {
        let mut parser = Parser {
            state: ParserState::Text,
        };

        let result: Cow<str> = self
            .chars()
            .filter(move |cur| {
                match parser.state {
                    ParserState::Text if *cur == '\x03' => {
                        parser.state = ParserState::ColorCode;
                        false
                    },
                    ParserState::Text => !['\x02', '\x1F', '\x16', '\x0F'].contains(cur),
                    ParserState::ColorCode if  (*cur).is_digit(10) => {
                        parser.state = ParserState::Foreground1;
                        false
                    },
                    ParserState::Foreground1 if (*cur).is_digit(6) => {
                        parser.state = ParserState::Foreground2;
                        false
                    },
                    ParserState::Foreground1 if *cur == ','  => {
                        parser.state = ParserState::Comma;
                        false
                    },
                    ParserState::Foreground2 if *cur == ',' => {
                        parser.state = ParserState::Comma;
                        false
                    },
                    ParserState::Comma if ((*cur).is_digit(10)) => {
                        parser.state = ParserState::Background1;
                        false
                    },
                    ParserState::Background1 if (*cur).is_digit(6) => {
                        parser.state = ParserState::Text;
                        false
                    }
                    _ => true
                }
            })
            .collect();

        result
    }

}

impl FormattedStringExt for String {
    fn is_formatted(&self) -> bool {
        (&self[..]).is_formatted()
    }
    fn strip_formatting(&self) -> Cow<str> {
        (&self[..]).strip_formatting()
    }
}
<commit_msg>add tests for formatted strings (#130)<commit_after>//! An extension trait that provides the ability to strip IRC colors from a string
use std::borrow::Cow;

#[derive(PartialEq)]
enum ParserState {
    Text,
    ColorCode,
    Foreground1,
    Foreground2,
    Comma,
    Background1,
}
struct Parser {
    state: ParserState,
}

/// An extension trait giving strings a function to strip IRC colors
pub trait FormattedStringExt {

    /// Returns true if the string contains color, bold, underline or italics
    fn is_formatted(&self) -> bool;

    /// Returns the string with all color, bold, underline and italics stripped
    fn strip_formatting(&self) -> Cow<str>;

}

impl FormattedStringExt for str {
    fn is_formatted(&self) -> bool {
        self.contains('\x02') || // bold
            self.contains('\x1F') || // underline
            self.contains('\x16') || // reverse
            self.contains('\x0F') || // normal
            self.contains('\x03') // color
    }

    fn strip_formatting(&self) -> Cow<str> {
        let mut parser = Parser {
            state: ParserState::Text,
        };

        let result: Cow<str> = self
            .chars()
            .filter(move |cur| {
                match parser.state {
                    ParserState::Text if *cur == '\x03' => {
                        parser.state = ParserState::ColorCode;
                        false
                    },
                    ParserState::Text => !['\x02', '\x1F', '\x16', '\x0F'].contains(cur),
                    ParserState::ColorCode if  (*cur).is_digit(10) => {
                        parser.state = ParserState::Foreground1;
                        false
                    },
                    ParserState::Foreground1 if (*cur).is_digit(6) => {
                        parser.state = ParserState::Foreground2;
                        false
                    },
                    ParserState::Foreground1 if *cur == ','  => {
                        parser.state = ParserState::Comma;
                        false
                    },
                    ParserState::Foreground2 if *cur == ',' => {
                        parser.state = ParserState::Comma;
                        false
                    },
                    ParserState::Comma if ((*cur).is_digit(10)) => {
                        parser.state = ParserState::Background1;
                        false
                    },
                    ParserState::Background1 if (*cur).is_digit(6) => {
                        parser.state = ParserState::Text;
                        false
                    }
                    _ => true
                }
            })
            .collect();

        result
    }

}

impl FormattedStringExt for String {
    fn is_formatted(&self) -> bool {
        (&self[..]).is_formatted()
    }
    fn strip_formatting(&self) -> Cow<str> {
        (&self[..]).strip_formatting()
    }
}

#[cfg(test)]
mod test {
    use proto::colors::FormattedStringExt;

    #[test]
    fn test_strip_bold() {
        assert_eq!("l\x02ol".strip_formatting(), "lol");
    }

    #[test]
    fn test_strip_fg_color() {
        assert_eq!("l\x033ol".strip_formatting(), "lol");
    }

    #[test]
    fn test_strip_fg_color2() {
        assert_eq!("l\x0312ol".strip_formatting(), "lol");
    }

    #[test]
    fn test_strip_fg_bg_11() {
        assert_eq!("l\x031,2ol".strip_formatting(), "lol");
    }
    #[test]
    fn test_strip_fg_bg_21() {
        assert_eq!("l\x0312,3ol".strip_formatting(), "lol");
    }
    #[test]
    fn test_strip_fg_bg_12() {
        assert_eq!("l\x031,12ol".strip_formatting(), "lol");
    }
    #[test]
    fn test_strip_fg_bg_22() {
        assert_eq!("l\x0312,13ol".strip_formatting(), "lol");
    }
}<|endoftext|>


<commit_before>pub fn pow_mod(n: u64, m: u64, d: u64) -> u64 {
    if n < 100 && d < 400_000_000 {
        // k * k * n < 2^64 - 1
        pow_mod_u64(n, m, d)
    } else {
        pow_mod_u128(n as u128, m as u128, d as u128) as u64
    }
}

fn pow_mod_u64(n: u64, m: u64, d: u64) -> u64 {
    if m == 0 {
        1 % d
    } else if m == 1 {
        n % d
    } else {
        let k = pow_mod_u64(n, m / 2, d);
        if m % 2 == 0 {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}

// TODO: use generics; num package does not seem to support u128
fn pow_mod_u128(n: u128, m: u128, d: u128) -> u128 {
    if m == 0 {
        1 % d
    } else if m == 1 {
        n % d
    } else {
        let k = pow_mod_u128(n, m / 2, d);
        if m % 2 == 0 {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}

#[test]
fn pow_mod_test() {
    const TEST_CASES: &[(u64, u64, u64, u64)] = &[
        (0, 0, 7, 1),
        (12, 0, 7, 1),
        (12, 1, 7, 5),
        (12, 2, 7, 4),
        (12, 3, 7, 6),
        (12, 65536, 7, 2),
        (16777215, 16777216, 31, 16),
        (68719476735, 68719476736, 16777215, 32760),
        (68719476735, 68719476736, 68719476734, 1),
        (37, 9007199254740991, 281474976710655, 126094628322028),
        (65535, 4294967295, 281474976710655, 184618294348860),
    ];
    for &(n, m, d, r) in TEST_CASES {
        assert_eq!((n, m, d, pow_mod(n, m, d)), (n, m, d, r));
    }
}
<commit_msg>use trait for calculating pow_mod<commit_after>pub fn pow_mod(n: u64, m: u64, d: u64) -> u64 {
    if n < 100 && d < 400_000_000 {
        // k * k * n < 2^64 - 1
        pow_mod_inner(n, m, d)
    } else {
        pow_mod_inner(n as u128, m as u128, d as u128) as u64
    }
}

fn pow_mod_inner<T>(n: T, m: T, d: T) -> T
where
    T: Copy
        + std::cmp::PartialEq
        + std::ops::Mul<Output = T>
        + std::ops::Div<Output = T>
        + std::ops::Rem<Output = T>
        + std::convert::From<u64>,
{
    if m == 0.into() {
        if d == 1.into() {
            0.into()
        } else {
            1.into()
        }
    } else if m == 1.into() {
        n % d
    } else {
        let k = pow_mod_inner(n, m / 2.into(), d);
        if m % 2.into() == 0.into() {
            (k * k) % d
        } else {
            (k * k * n) % d
        }
    }
}

#[test]
fn pow_mod_test() {
    const TEST_CASES: &[(u64, u64, u64, u64)] = &[
        (0, 0, 1, 0),
        (0, 0, 7, 1),
        (12, 0, 7, 1),
        (12, 1, 7, 5),
        (12, 2, 7, 4),
        (12, 3, 7, 6),
        (12, 65536, 7, 2),
        (16777215, 16777216, 31, 16),
        (68719476735, 68719476736, 16777215, 32760),
        (68719476735, 68719476736, 68719476734, 1),
        (37, 9007199254740991, 281474976710655, 126094628322028),
        (65535, 4294967295, 281474976710655, 184618294348860),
    ];
    for &(n, m, d, r) in TEST_CASES {
        assert_eq!((n, m, d, pow_mod(n, m, d)), (n, m, d, r));
    }
}
<|endoftext|>


<commit_before>use std::num::Zero;
use std::util;
use nalgebra::na::Indexable;
use nalgebra::na;
use ray::{Ray, RayCast};
use bounding_volume;
use math::{N, V};

impl RayCast for bounding_volume::AABB {
    fn toi_with_ray(&self, ray: &Ray) -> Option<N> {
        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();

        for i in range(0u, na::dim::<V>()) {
            if ray.dir.at(i).is_zero() {
                if ray.orig.at(i) < self.mins().at(i) || ray.orig.at(i) > self.maxs().at(i) {
                    return None
                }
            }
            else {
                let _1: N = na::one();
                let denom = _1 / ray.dir.at(i);
                let mut inter_with_near_plane = (self.mins().at(i) - ray.orig.at(i)) * denom;
                let mut inter_with_far_plane  = (self.maxs().at(i) - ray.orig.at(i)) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    util::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }

                tmin = tmin.max(&inter_with_near_plane);
                tmax = tmax.min(&inter_with_far_plane);

                if tmin > tmax {
                    return None;
                }
            }
        }

        Some(tmin)
    }

    fn toi_and_normal_with_ray(&self, ray: &Ray) -> Option<(N, V)> {
        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();
        let mut side = 0;
        let mut diag = false;

        for i in range(0u, na::dim::<V>()) {
            if ray.dir.at(i).is_zero() {
                if ray.orig.at(i) < self.mins().at(i) || ray.orig.at(i) > self.maxs().at(i) {
                    return None
                }
            }
            else {
                let _1: N = na::one();
                let denom = _1 / ray.dir.at(i);
                let flip_sides;
                let mut inter_with_near_plane = (self.mins().at(i) - ray.orig.at(i)) * denom;
                let mut inter_with_far_plane  = (self.maxs().at(i) - ray.orig.at(i)) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    flip_sides = true;
                    util::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }
                else {
                    flip_sides = false;
                }

                if inter_with_near_plane > tmin {
                    tmin = inter_with_near_plane;
                    side = if flip_sides { -(i as int) } else { i as int };
                    diag = false;
                }
                else if inter_with_near_plane == tmin {
                    diag = true;
                }

                tmax = tmax.min(&inter_with_far_plane);

                if tmin > tmax {
                    return None;
                }
            }
        }

        if diag {
            Some((tmin, -na::normalize(&ray.dir)))
        }
        else {
            let mut normal: V = na::zero();

            if side < 0 {
                normal.set((-side) as uint, na::one::<N>());
            }
            else {
                normal.set(side as uint, -na::one::<N>());
            }
            Some((tmin, normal))
        }
    }
}
<commit_msg>Fix normal computation for ray cast against aabb.<commit_after>use std::num::Zero;
use std::util;
use nalgebra::na::Indexable;
use nalgebra::na;
use ray::{Ray, RayCast};
use bounding_volume;
use math::{N, V};

impl RayCast for bounding_volume::AABB {
    fn toi_with_ray(&self, ray: &Ray) -> Option<N> {
        let mut tmin: N = na::zero();
        let mut tmax: N = Bounded::max_value();

        for i in range(0u, na::dim::<V>()) {
            if ray.dir.at(i).is_zero() {
                if ray.orig.at(i) < self.mins().at(i) || ray.orig.at(i) > self.maxs().at(i) {
                    return None
                }
            }
            else {
                let _1: N = na::one();
                let denom = _1 / ray.dir.at(i);
                let mut inter_with_near_plane = (self.mins().at(i) - ray.orig.at(i)) * denom;
                let mut inter_with_far_plane  = (self.maxs().at(i) - ray.orig.at(i)) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    util::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }

                tmin = tmin.max(&inter_with_near_plane);
                tmax = tmax.min(&inter_with_far_plane);

                if tmin > tmax {
                    return None;
                }
            }
        }

        Some(tmin)
    }

    fn toi_and_normal_with_ray(&self, ray: &Ray) -> Option<(N, V)> {
        let mut tmax: N = Bounded::max_value();
        let mut tmin: N = -tmax;
        let mut side = 0;
        let mut diag = false;

        for i in range(0u, na::dim::<V>()) {
            if ray.dir.at(i).is_zero() {
                if ray.orig.at(i) < self.mins().at(i) || ray.orig.at(i) > self.maxs().at(i) {
                    return None
                }
            }
            else {
                let _1: N = na::one();
                let denom = _1 / ray.dir.at(i);
                let flip_sides;
                let mut inter_with_near_plane = (self.mins().at(i) - ray.orig.at(i)) * denom;
                let mut inter_with_far_plane  = (self.maxs().at(i) - ray.orig.at(i)) * denom;

                if inter_with_near_plane > inter_with_far_plane {
                    flip_sides = true;
                    util::swap(&mut inter_with_near_plane, &mut inter_with_far_plane)
                }
                else {
                    flip_sides = false;
                }

                if inter_with_near_plane > tmin {
                    tmin = inter_with_near_plane;
                    side = if flip_sides { -(i as int + 1) } else { i as int + 1 };
                    diag = false;
                }
                else if inter_with_near_plane == tmin {
                    diag = true;
                }

                tmax = tmax.min(&inter_with_far_plane);

                if tmin > tmax {
                    return None;
                }
            }
        }

        if tmin < na::cast(0.0) {
            return None;
        }

        if diag {
            Some((tmin, -na::normalize(&ray.dir)))
        }
        else {
            let mut normal: V = na::zero();

            if side < 0 {
                normal.set((-side - 1) as uint, na::one::<N>());
            }
            else {
                normal.set((side - 1) as uint, -na::one::<N>());
            }
            Some((tmin, normal))
        }
    }
}
<|endoftext|>


<commit_before>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;
use std::string;

/// A specialized `std::result::Result` type for FBX parsing.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug)]
pub struct Error {
    /// Last position of successfully read data when an error detected.
    pos: u64,
    /// Error type.
    kind: ErrorKind,
}

impl Error {
    /// Constructs `Error` with position and objects which can be converted to `ErrorKind`.
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

/// Error type.
#[derive(Debug)]
pub enum ErrorKind {
    /// Conversion from array of u8 to String failed.
    FromUtf8Error(string::FromUtf8Error),
    /// Invalid magic binary detected.
    InvalidMagic,
    /// I/O operation error.
    Io(io::Error),
    /// Corrupted or inconsistent FBX data detected.
    DataError(String),
    /// Got an unexpected value, and cannot continue parsing.
    ///
    /// This is specialization of `DataError`.
    UnexpectedValue(String),
    /// Reached unexpected EOF.
    UnexpectedEof,
    /// Attempted to use unimplemented feature.
    Unimplemented(String),
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::FromUtf8Error(err)
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        // TODO: `io::Error::UnexpectedEof` should be converted to `ErrorKind::UnexpectedEof`.
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<commit_msg>Implement `std::fmt::Display` trait for `reader::error::Error`<commit_after>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;
use std::string;
use std::fmt;

/// A specialized `std::result::Result` type for FBX parsing.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug)]
pub struct Error {
    /// Last position of successfully read data when an error detected.
    pos: u64,
    /// Error type.
    kind: ErrorKind,
}

impl Error {
    /// Constructs `Error` with position and objects which can be converted to `ErrorKind`.
    pub fn new<K: Into<ErrorKind>>(pos: u64, kind: K) -> Self {
        Error {
            pos: pos,
            kind: kind.into(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind {
            ErrorKind::FromUtf8Error(ref err) => write!(f, "UTF-8 conversion error at pos={}: {}", self.pos, err),
            ErrorKind::InvalidMagic => write!(f, "Invalid magic header at pos={}: Non-FBX or corrupted data?", self.pos),
            ErrorKind::Io(ref err) => write!(f, "I/O error at pos={}: {}", self.pos, err),
            ErrorKind::DataError(ref err) => write!(f, "Invalid data at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedValue(ref err) => write!(f, "Got an unexpected value at pos={}: {}", self.pos, err),
            ErrorKind::UnexpectedEof => write!(f, "Unexpected EOF at pos={}", self.pos),
            ErrorKind::Unimplemented(ref err) => write!(f, "Unimplemented feature: {}", err),
        }
    }
}

/// Error type.
#[derive(Debug)]
pub enum ErrorKind {
    /// Conversion from array of u8 to String failed.
    FromUtf8Error(string::FromUtf8Error),
    /// Invalid magic binary detected.
    InvalidMagic,
    /// I/O operation error.
    Io(io::Error),
    /// Corrupted or inconsistent FBX data detected.
    DataError(String),
    /// Got an unexpected value, and cannot continue parsing.
    ///
    /// This is specialization of `DataError`.
    UnexpectedValue(String),
    /// Reached unexpected EOF.
    UnexpectedEof,
    /// Attempted to use unimplemented feature.
    Unimplemented(String),
}

impl From<string::FromUtf8Error> for ErrorKind {
    fn from(err: string::FromUtf8Error) -> ErrorKind {
        ErrorKind::FromUtf8Error(err)
    }
}

impl From<io::Error> for ErrorKind {
    fn from(err: io::Error) -> ErrorKind {
        // TODO: `io::Error::UnexpectedEof` should be converted to `ErrorKind::UnexpectedEof`.
        ErrorKind::Io(err)
    }
}

impl From<byteorder::Error> for ErrorKind {
    fn from(err: byteorder::Error) -> ErrorKind {
        match err {
            byteorder::Error::UnexpectedEOF => ErrorKind::UnexpectedEof,
            byteorder::Error::Io(err) => ErrorKind::Io(err),
        }
    }
}
<|endoftext|>