<commit_before>use std::net::Shutdown;
use std::{io, mem, time};

use bytes::{Buf, BufMut, BytesMut};
use futures::{Async, Future, Poll};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_timer::Delay;

use super::error::HttpDispatchError;
use super::settings::ServiceConfig;
use super::{h1, h2, HttpHandler, IoStream};
use http::StatusCode;

const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";

pub(crate) enum HttpProtocol<T: IoStream, H: HttpHandler + 'static> {
    H1(h1::Http1Dispatcher<T, H>),
    H2(h2::Http2<T, H>),
    Unknown(ServiceConfig<H>, T, BytesMut),
    None,
}

impl<T: IoStream, H: HttpHandler + 'static> HttpProtocol<T, H> {
    pub(crate) fn shutdown(&mut self) {
        match self {
            HttpProtocol::H1(ref mut h1) => {
                let io = h1.io();
                let _ = IoStream::set_linger(io, Some(time::Duration::new(0, 0)));
                let _ = IoStream::shutdown(io, Shutdown::Both);
            }
            HttpProtocol::H2(ref mut h2) => h2.shutdown(),
            HttpProtocol::Unknown(_, io, _) => {
                let _ = IoStream::set_linger(io, Some(time::Duration::new(0, 0)));
                let _ = IoStream::shutdown(io, Shutdown::Both);
            }
            HttpProtocol::None => (),
        }
    }
}

enum ProtocolKind {
    Http1,
    Http2,
}

#[doc(hidden)]
pub struct HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    node: Node<HttpProtocol<T, H>>,
    node_reg: bool,
    ka_timeout: Option<Delay>,
}

impl<T, H> HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    pub(crate) fn new(settings: ServiceConfig<H>, io: T) -> HttpChannel<T, H> {
        let ka_timeout = settings.client_timer();

        HttpChannel {
            ka_timeout,
            node_reg: false,
            node: Node::new(HttpProtocol::Unknown(
                settings,
                io,
                BytesMut::with_capacity(8192),
            )),
        }
    }
}

impl<T, H> Drop for HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    fn drop(&mut self) {
        self.node.remove();
    }
}

impl<T, H> Future for HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    type Item = ();
    type Error = HttpDispatchError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // keep-alive timer
        if self.ka_timeout.is_some() {
            match self.ka_timeout.as_mut().unwrap().poll() {
                Ok(Async::Ready(_)) => {
                    trace!("Slow request timed out, close connection");
                    let proto = mem::replace(self.node.get_mut(), HttpProtocol::None);
                    if let HttpProtocol::Unknown(settings, io, buf) = proto {
                        *self.node.get_mut() =
                            HttpProtocol::H1(h1::Http1Dispatcher::for_error(
                                settings,
                                io,
                                StatusCode::REQUEST_TIMEOUT,
                                self.ka_timeout.take(),
                                buf,
                            ));
                        return self.poll();
                    }
                    return Ok(Async::Ready(()));
                }
                Ok(Async::NotReady) => (),
                Err(_) => panic!("Something is really wrong"),
            }
        }

        if !self.node_reg {
            self.node_reg = true;
            let settings = match self.node.get_mut() {
                HttpProtocol::H1(ref mut h1) => h1.settings().clone(),
                HttpProtocol::H2(ref mut h2) => h2.settings().clone(),
                HttpProtocol::Unknown(ref mut settings, _, _) => settings.clone(),
                HttpProtocol::None => unreachable!(),
            };
            settings.head().insert(&mut self.node);
        }

        let mut is_eof = false;
        let kind = match self.node.get_mut() {
            HttpProtocol::H1(ref mut h1) => return h1.poll(),
            HttpProtocol::H2(ref mut h2) => return h2.poll(),
            HttpProtocol::Unknown(_, ref mut io, ref mut buf) => {
                let mut err = None;
                let mut disconnect = false;
                match io.read_available(buf) {
                    Ok(Async::Ready((read_some, stream_closed))) => {
                        is_eof = stream_closed;
                        // Only disconnect if no data was read.
                        if is_eof && !read_some {
                            disconnect = true;
                        }
                    }
                    Err(e) => {
                        err = Some(e.into());
                    }
                    _ => (),
                }
                if disconnect {
                    debug!("Ignored premature client disconnection");
                    return Ok(Async::Ready(()));
                } else if let Some(e) = err {
                    return Err(e);
                }

                if buf.len() >= 14 {
                    if buf[..14] == HTTP2_PREFACE[..] {
                        ProtocolKind::Http2
                    } else {
                        ProtocolKind::Http1
                    }
                } else {
                    return Ok(Async::NotReady);
                }
            }
            HttpProtocol::None => unreachable!(),
        };

        // upgrade to specific http protocol
        let proto = mem::replace(self.node.get_mut(), HttpProtocol::None);
        if let HttpProtocol::Unknown(settings, io, buf) = proto {
            match kind {
                ProtocolKind::Http1 => {
                    *self.node.get_mut() = HttpProtocol::H1(h1::Http1Dispatcher::new(
                        settings,
                        io,
                        buf,
                        is_eof,
                        self.ka_timeout.take(),
                    ));
                    return self.poll();
                }
                ProtocolKind::Http2 => {
                    *self.node.get_mut() = HttpProtocol::H2(h2::Http2::new(
                        settings,
                        io,
                        buf.freeze(),
                        self.ka_timeout.take(),
                    ));
                    return self.poll();
                }
            }
        }
        unreachable!()
    }
}

#[doc(hidden)]
pub struct H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    node: Node<HttpProtocol<T, H>>,
    node_reg: bool,
}

impl<T, H> H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    pub(crate) fn new(settings: ServiceConfig<H>, io: T) -> H1Channel<T, H> {
        H1Channel {
            node_reg: false,
            node: Node::new(HttpProtocol::H1(h1::Http1Dispatcher::new(
                settings,
                io,
                BytesMut::with_capacity(8192),
                false,
                None,
            ))),
        }
    }
}

impl<T, H> Drop for H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    fn drop(&mut self) {
        self.node.remove();
    }
}

impl<T, H> Future for H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    type Item = ();
    type Error = HttpDispatchError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if !self.node_reg {
            self.node_reg = true;
            let settings = match self.node.get_mut() {
                HttpProtocol::H1(ref mut h1) => h1.settings().clone(),
                _ => unreachable!(),
            };
            settings.head().insert(&mut self.node);
        }

        match self.node.get_mut() {
            HttpProtocol::H1(ref mut h1) => h1.poll(),
            _ => unreachable!(),
        }
    }
}

pub(crate) struct Node<T> {
    next: Option<*mut Node<T>>,
    prev: Option<*mut Node<T>>,
    element: T,
}

impl<T> Node<T> {
    fn new(element: T) -> Self {
        Node {
            element,
            next: None,
            prev: None,
        }
    }

    fn get_mut(&mut self) -> &mut T {
        &mut self.element
    }

    fn insert<I>(&mut self, next_el: &mut Node<I>) {
        let next: *mut Node<T> = next_el as *const _ as *mut _;

        if let Some(next2) = self.next {
            unsafe {
                let n = next2.as_mut().unwrap();
                n.prev = Some(next);
            }
            next_el.next = Some(next2 as *mut _);
        }
        self.next = Some(next);

        unsafe {
            let next: &mut Node<T> = &mut *next;
            next.prev = Some(self as *mut _);
        }
    }

    fn remove(&mut self) {
        let next = self.next.take();
        let prev = self.prev.take();

        if let Some(prev) = prev {
            unsafe {
                prev.as_mut().unwrap().next = next;
            }
        }
        if let Some(next) = next {
            unsafe {
                next.as_mut().unwrap().prev = prev;
            }
        }
    }
}

impl Node<()> {
    pub(crate) fn head() -> Self {
        Node {
            next: None,
            prev: None,
            element: (),
        }
    }

    pub(crate) fn traverse<T, H, F: Fn(&mut HttpProtocol<T, H>)>(&self, f: F)
    where
        T: IoStream,
        H: HttpHandler + 'static,
    {
        if let Some(n) = self.next.as_ref() {
            unsafe {
                let mut next: &mut Node<HttpProtocol<T, H>> =
                    &mut *(n.as_ref().unwrap() as *const _ as *mut _);
                loop {
                    f(&mut next.element);

                    next = if let Some(n) = next.next.as_ref() {
                        &mut **n
                    } else {
                        return;
                    }
                }
            }
        }
    }
}

/// Wrapper for `AsyncRead + AsyncWrite` types
pub(crate) struct WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    io: T,
}

impl<T> WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    pub fn new(io: T) -> Self {
        WrapperStream { io }
    }
}

impl<T> IoStream for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn shutdown(&mut self, _: Shutdown) -> io::Result<()> {
        Ok(())
    }
    #[inline]
    fn set_nodelay(&mut self, _: bool) -> io::Result<()> {
        Ok(())
    }
    #[inline]
    fn set_linger(&mut self, _: Option<time::Duration>) -> io::Result<()> {
        Ok(())
    }
    #[inline]
    fn set_keepalive(&mut self, _: Option<time::Duration>) -> io::Result<()> {
        Ok(())
    }
}

impl<T> io::Read for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.io.read(buf)
    }
}

impl<T> io::Write for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.io.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

impl<T> AsyncRead for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
        self.io.read_buf(buf)
    }
}

impl<T> AsyncWrite for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.io.shutdown()
    }
    #[inline]
    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
        self.io.write_buf(buf)
    }
}
<commit_msg>disable shutdown atm<commit_after>use std::net::Shutdown;
use std::{io, mem, time};

use bytes::{Buf, BufMut, BytesMut};
use futures::{Async, Future, Poll};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_timer::Delay;

use super::error::HttpDispatchError;
use super::settings::ServiceConfig;
use super::{h1, h2, HttpHandler, IoStream};
use http::StatusCode;

const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";

pub(crate) enum HttpProtocol<T: IoStream, H: HttpHandler + 'static> {
    H1(h1::Http1Dispatcher<T, H>),
    H2(h2::Http2<T, H>),
    Unknown(ServiceConfig<H>, T, BytesMut),
    None,
}

impl<T: IoStream, H: HttpHandler + 'static> HttpProtocol<T, H> {
    pub(crate) fn shutdown(&mut self) {
        match self {
            HttpProtocol::H1(ref mut h1) => {
                let io = h1.io();
                let _ = IoStream::set_linger(io, Some(time::Duration::new(0, 0)));
                let _ = IoStream::shutdown(io, Shutdown::Both);
            }
            HttpProtocol::H2(ref mut h2) => h2.shutdown(),
            HttpProtocol::Unknown(_, io, _) => {
                let _ = IoStream::set_linger(io, Some(time::Duration::new(0, 0)));
                let _ = IoStream::shutdown(io, Shutdown::Both);
            }
            HttpProtocol::None => (),
        }
    }
}

enum ProtocolKind {
    Http1,
    Http2,
}

#[doc(hidden)]
pub struct HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    proto: HttpProtocol<T, H>,
    node: Option<Node<()>>,
    ka_timeout: Option<Delay>,
}

impl<T, H> HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    pub(crate) fn new(settings: ServiceConfig<H>, io: T) -> HttpChannel<T, H> {
        let ka_timeout = settings.client_timer();

        HttpChannel {
            ka_timeout,
            node: None,
            proto: HttpProtocol::Unknown(settings, io, BytesMut::with_capacity(8192)),
        }
    }
}

impl<T, H> Drop for HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    fn drop(&mut self) {
        if let Some(mut node) = self.node.take() {
            node.remove()
        }
    }
}

impl<T, H> Future for HttpChannel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    type Item = ();
    type Error = HttpDispatchError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        // keep-alive timer
        if self.ka_timeout.is_some() {
            match self.ka_timeout.as_mut().unwrap().poll() {
                Ok(Async::Ready(_)) => {
                    trace!("Slow request timed out, close connection");
                    let proto = mem::replace(&mut self.proto, HttpProtocol::None);
                    if let HttpProtocol::Unknown(settings, io, buf) = proto {
                        self.proto = HttpProtocol::H1(h1::Http1Dispatcher::for_error(
                            settings,
                            io,
                            StatusCode::REQUEST_TIMEOUT,
                            self.ka_timeout.take(),
                            buf,
                        ));
                        return self.poll();
                    }
                    return Ok(Async::Ready(()));
                }
                Ok(Async::NotReady) => (),
                Err(_) => panic!("Something is really wrong"),
            }
        }

        if self.node.is_none() {
            self.node = Some(Node::new(()));
            let _ = match self.proto {
                HttpProtocol::H1(ref mut h1) => {
                    self.node.as_mut().map(|n| h1.settings().head().insert(n))
                }
                HttpProtocol::H2(ref mut h2) => {
                    self.node.as_mut().map(|n| h2.settings().head().insert(n))
                }
                HttpProtocol::Unknown(ref mut settings, _, _) => {
                    self.node.as_mut().map(|n| settings.head().insert(n))
                }
                HttpProtocol::None => unreachable!(),
            };
        }

        let mut is_eof = false;
        let kind = match self.proto {
            HttpProtocol::H1(ref mut h1) => return h1.poll(),
            HttpProtocol::H2(ref mut h2) => return h2.poll(),
            HttpProtocol::Unknown(_, ref mut io, ref mut buf) => {
                let mut err = None;
                let mut disconnect = false;
                match io.read_available(buf) {
                    Ok(Async::Ready((read_some, stream_closed))) => {
                        is_eof = stream_closed;
                        // Only disconnect if no data was read.
                        if is_eof && !read_some {
                            disconnect = true;
                        }
                    }
                    Err(e) => {
                        err = Some(e.into());
                    }
                    _ => (),
                }
                if disconnect {
                    debug!("Ignored premature client disconnection");
                    return Ok(Async::Ready(()));
                } else if let Some(e) = err {
                    return Err(e);
                }

                if buf.len() >= 14 {
                    if buf[..14] == HTTP2_PREFACE[..] {
                        ProtocolKind::Http2
                    } else {
                        ProtocolKind::Http1
                    }
                } else {
                    return Ok(Async::NotReady);
                }
            }
            HttpProtocol::None => unreachable!(),
        };

        // upgrade to specific http protocol
        let proto = mem::replace(&mut self.proto, HttpProtocol::None);
        if let HttpProtocol::Unknown(settings, io, buf) = proto {
            match kind {
                ProtocolKind::Http1 => {
                    self.proto = HttpProtocol::H1(h1::Http1Dispatcher::new(
                        settings,
                        io,
                        buf,
                        is_eof,
                        self.ka_timeout.take(),
                    ));
                    return self.poll();
                }
                ProtocolKind::Http2 => {
                    self.proto = HttpProtocol::H2(h2::Http2::new(
                        settings,
                        io,
                        buf.freeze(),
                        self.ka_timeout.take(),
                    ));
                    return self.poll();
                }
            }
        }
        unreachable!()
    }
}

#[doc(hidden)]
pub struct H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    proto: HttpProtocol<T, H>,
    node: Option<Node<()>>,
}

impl<T, H> H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    pub(crate) fn new(settings: ServiceConfig<H>, io: T) -> H1Channel<T, H> {
        H1Channel {
            node: None,
            proto: HttpProtocol::H1(h1::Http1Dispatcher::new(
                settings,
                io,
                BytesMut::with_capacity(8192),
                false,
                None,
            )),
        }
    }
}

impl<T, H> Drop for H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    fn drop(&mut self) {
        if let Some(mut node) = self.node.take() {
            node.remove();
        }
    }
}

impl<T, H> Future for H1Channel<T, H>
where
    T: IoStream,
    H: HttpHandler + 'static,
{
    type Item = ();
    type Error = HttpDispatchError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        if self.node.is_none() {
            self.node = Some(Node::new(()));
            match self.proto {
                HttpProtocol::H1(ref mut h1) => {
                    self.node.as_mut().map(|n| h1.settings().head().insert(n));
                }
                _ => unreachable!(),
            };
        }

        match self.proto {
            HttpProtocol::H1(ref mut h1) => h1.poll(),
            _ => unreachable!(),
        }
    }
}

pub(crate) struct Node<T> {
    next: Option<*mut Node<T>>,
    prev: Option<*mut Node<T>>,
    element: T,
}

impl<T> Node<T> {
    fn new(element: T) -> Self {
        Node {
            element,
            next: None,
            prev: None,
        }
    }

    fn insert<I>(&mut self, next_el: &mut Node<I>) {
        let next: *mut Node<T> = next_el as *const _ as *mut _;

        if let Some(next2) = self.next {
            unsafe {
                let n = next2.as_mut().unwrap();
                n.prev = Some(next);
            }
            next_el.next = Some(next2 as *mut _);
        }
        self.next = Some(next);

        unsafe {
            let next: &mut Node<T> = &mut *next;
            next.prev = Some(self as *mut _);
        }
    }

    fn remove(&mut self) {
        let next = self.next.take();
        let prev = self.prev.take();

        if let Some(prev) = prev {
            unsafe {
                prev.as_mut().unwrap().next = next;
            }
        }
        if let Some(next) = next {
            unsafe {
                next.as_mut().unwrap().prev = prev;
            }
        }
    }
}

impl Node<()> {
    pub(crate) fn head() -> Self {
        Node {
            next: None,
            prev: None,
            element: (),
        }
    }

    pub(crate) fn traverse<T, H, F: Fn(&mut HttpProtocol<T, H>)>(&self, f: F)
    where
        T: IoStream,
        H: HttpHandler + 'static,
    {
        if let Some(n) = self.next.as_ref() {
            unsafe {
                let mut next: &mut Node<HttpProtocol<T, H>> =
                    &mut *(n.as_ref().unwrap() as *const _ as *mut _);
                loop {
                    f(&mut next.element);

                    next = if let Some(n) = next.next.as_ref() {
                        &mut **n
                    } else {
                        return;
                    }
                }
            }
        }
    }
}

/// Wrapper for `AsyncRead + AsyncWrite` types
pub(crate) struct WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    io: T,
}

impl<T> WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    pub fn new(io: T) -> Self {
        WrapperStream { io }
    }
}

impl<T> IoStream for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn shutdown(&mut self, _: Shutdown) -> io::Result<()> {
        Ok(())
    }
    #[inline]
    fn set_nodelay(&mut self, _: bool) -> io::Result<()> {
        Ok(())
    }
    #[inline]
    fn set_linger(&mut self, _: Option<time::Duration>) -> io::Result<()> {
        Ok(())
    }
    #[inline]
    fn set_keepalive(&mut self, _: Option<time::Duration>) -> io::Result<()> {
        Ok(())
    }
}

impl<T> io::Read for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.io.read(buf)
    }
}

impl<T> io::Write for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.io.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.io.flush()
    }
}

impl<T> AsyncRead for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn read_buf<B: BufMut>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
        self.io.read_buf(buf)
    }
}

impl<T> AsyncWrite for WrapperStream<T>
where
    T: AsyncRead + AsyncWrite + 'static,
{
    #[inline]
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        self.io.shutdown()
    }
    #[inline]
    fn write_buf<B: Buf>(&mut self, buf: &mut B) -> Poll<usize, io::Error> {
        self.io.write_buf(buf)
    }
}
<|endoftext|>


<commit_before>#![warn(unused_variables)]
extern crate rust_base58;
extern crate serde_json;
extern crate zmq;

use self::rust_base58::FromBase58;
use std::cell::RefCell;
use std::thread;

use commands::{Command, CommandExecutor};
use commands::agent::AgentCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use utils::json::{JsonDecodable, JsonEncodable};
use utils::sequence::SequenceUtils;

struct RemoteAgent {
    socket: zmq::Socket,
    addr: String,
    public_key: Vec<u8>,
    secret_key: Vec<u8>,
    server_key: Vec<u8>,
    conn_handle: i32,
}

struct AgentWorker {
    cmd_socket: zmq::Socket,
    agent_connections: Vec<RemoteAgent>,
}

struct Agent {
    cmd_socket: zmq::Socket,
    worker: Option<thread::JoinHandle<()>>,
}

impl Drop for Agent {
    fn drop(&mut self) {
        trace!("agent drop >>");
        self.cmd_socket.send_str(AgentWorkerCommand::Exit.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap(); //TODO
        self.worker.take().unwrap().join().unwrap();
        trace!("agent drop <<");
    }
}

pub struct AgentService {
    agent: RefCell<Option<Agent>>,
}

impl Agent {
    pub fn new() -> Agent {
        let (send_soc, recv_soc) = _create_zmq_socket_pair("agent", true).unwrap();
        let mut worker = AgentWorker {
            cmd_socket: recv_soc,
            agent_connections: Vec::new(),
        };
        Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || { worker.run() }))
        }
    }
}

impl AgentService {
    pub fn new() -> AgentService {
        AgentService { agent: RefCell::new((None)) }
    }

    pub fn connect(&self, sender_did: &str, my_sk: &str, my_pk: &str, endpoint: &str, server_key: &str) -> Result<i32, CommonError> {
        let mut agent = self.agent.borrow_mut();
        if agent.is_none() {
            *agent = Some(Agent::new());
        }
        let conn_handle = SequenceUtils::get_next_id();
        let connect_cmd: AgentWorkerCommand = AgentWorkerCommand::Connect(ConnectCmd {
            did: sender_did.to_string(),
            secret_key: my_sk.to_string(),
            public_key: my_pk.to_string(),
            endpoint: endpoint.to_string(),
            server_key: server_key.to_string(),
            conn_handle: conn_handle,
        });
        agent.as_ref().unwrap().cmd_socket.send_str(connect_cmd.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap();
        Ok(conn_handle)
    }
}

impl AgentWorker {
    fn run(&mut self) {
        'agent_pool_loop: loop {
            trace!("agent worker poll loop >>");
            let cmds = self.poll().unwrap();
            for cmd in cmds {
                info!("received cmd {:?}", cmd);
                match cmd {
                    AgentWorkerCommand::Connect(cmd) => self.connect(&cmd).unwrap(),
                    AgentWorkerCommand::Response(resp) => self.agent_connections[resp.agent_ind].handle_response(resp.msg),
                    AgentWorkerCommand::Exit => break 'agent_pool_loop,
                }
            }
            trace!("agent worker poll loop <<");
        }
        trace!("agent poll finished");
    }

    fn connect(&mut self, cmd: &ConnectCmd) -> Result<(), PoolError> {
        let ra = RemoteAgent::new(cmd.public_key.as_str(), cmd.secret_key.as_str(),
                                  cmd.server_key.as_str(), cmd.endpoint.as_str(),
                                  cmd.conn_handle)
            .map_err(map_err_trace!("RemoteAgent::new failed"))?;
        ra.connect().map_err(map_err_trace!("RemoteAgent::connect failed"))?;
        self.agent_connections.push(ra);
        Ok(())
    }

    fn poll(&self) -> Result<Vec<AgentWorkerCommand>, zmq::Error> {
        let mut result = Vec::new();
        let mut poll_items: Vec<zmq::PollItem> = Vec::new();
        poll_items.push(self.cmd_socket.as_poll_item(zmq::POLLIN));

        for agent_conn in &self.agent_connections {
            poll_items.push(agent_conn.socket.as_poll_item(zmq::POLLIN));
        }

        zmq::poll(poll_items.as_mut_slice(), -1).map_err(map_err_trace!("agent poll failed"))?;

        if poll_items[0].is_readable() {
            let msg = self.cmd_socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
            info!("Input on cmd socket {}", msg);
            result.push(AgentWorkerCommand::from_json(msg.as_str()).unwrap());
        }

        for i in 0..self.agent_connections.len() {
            if poll_items[1 + i].is_readable() {
                let msg = self.agent_connections[i].socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
                info!("Input on agent socket {}: {}", i, msg);
                result.push(AgentWorkerCommand::Response(Response {
                    agent_ind: i,
                    msg: msg,
                }))
            }
        }

        Ok(result)
    }
}

impl RemoteAgent {
    fn new(pub_key: &str, sec_key: &str, ver_key: &str, addr: &str, conn_handle: i32) -> Result<RemoteAgent, PoolError> {
        Ok(RemoteAgent {
            socket: zmq::Context::new().socket(zmq::SocketType::DEALER)?,
            public_key: pub_key.from_base58()
                .map_err(|err| PoolError::CommonError(CommonError::InvalidStructure(format!("invalid pub_key {}", err))))?,
            secret_key: sec_key.from_base58()
                .map_err(|err| PoolError::CommonError(CommonError::InvalidStructure(format!("invalid sec_key {}", err))))?,
            server_key: ver_key.from_base58()
                .map_err(|err| PoolError::CommonError(CommonError::InvalidStructure(format!("invalid server_key {}", err))))?,
            addr: addr.to_string(),
            conn_handle: conn_handle,
        })
    }

    fn connect(&self) -> Result<(), PoolError> {
        impl From<zmq::EncodeError> for PoolError {
            fn from(err: zmq::EncodeError) -> PoolError {
                PoolError::CommonError(CommonError::InvalidState(format!("Invalid data stored RemoteAgent detected while connect {:?}", err)))
            }
        }
        self.socket.set_identity(zmq::z85_encode(self.public_key.as_slice())?.as_bytes())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_secretkey(zmq::z85_encode(self.secret_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_publickey(zmq::z85_encode(self.public_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_serverkey(zmq::z85_encode(self.server_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_linger(0).map_err(map_err_trace!())?; //TODO set correct timeout
        self.socket.connect(self.addr.as_str())
            .map_err(map_err_trace!("RemoteAgent::connect self.socket.connect failed"))?;
        self.socket.send_str("DID", zmq::DONTWAIT).map_err(map_err_trace!())?;
        Ok(())
    }

    fn handle_response(&self, msg: String) {
        if msg.eq("DID_ACK") {
            let send_res: Result<(), CommonError> =
                CommandExecutor::instance().send(
                    Command::Agent(
                        AgentCommand::ConnectAck(self.conn_handle, Ok(self.conn_handle))));
            if let Err(err) = send_res {
                error!("RemoteAgent::handle_response got connection ack, but can't send to client {}", err);
            };
        } else {
            //check state, transfer message to client
            unimplemented!();
        }
    }
}

#[serde(tag = "cmd")]
#[derive(Serialize, Deserialize, Debug)]
enum AgentWorkerCommand {
    Connect(ConnectCmd),
    Response(Response),
    Exit,
}

impl JsonEncodable for AgentWorkerCommand {}

impl<'a> JsonDecodable<'a> for AgentWorkerCommand {}

#[derive(Serialize, Deserialize, Debug)]
struct ConnectCmd {
    endpoint: String,
    did: String,
    secret_key: String,
    public_key: String,
    server_key: String,
    conn_handle: i32,
}

#[derive(Serialize, Deserialize, Debug)]
struct Response {
    agent_ind: usize,
    msg: String,
}

fn _create_zmq_socket_pair(address: &str, connect_and_bind: bool) -> Result<(zmq::Socket, zmq::Socket), zmq::Error> {
    let ctx = zmq::Context::new();
    let recv_soc = ctx.socket(zmq::SocketType::PAIR)?;
    let send_soc = ctx.socket(zmq::SocketType::PAIR)?;
    if connect_and_bind {
        let address = format!("inproc://{}", address);
        recv_soc.bind(&address)?;
        send_soc.connect(&address)?;
    }
    Ok((send_soc, recv_soc))
}

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

    use std::sync::mpsc::channel;
    use super::rust_base58::ToBase58;

    use utils::timeout::TimeoutUtils;

    #[test]
    fn agent_can_be_dropped() {
        let (sender, receiver) = channel();
        thread::spawn(move || {
            #[allow(unused_variables)]
            {
                let agent = Agent::new();
            }
            sender.send(true).unwrap();
        });
        receiver.recv_timeout(TimeoutUtils::short_timeout()).expect("drop not finished");
    }

    #[test]
    fn agent_service_connect_works() {
        let (sender, receiver) = channel();
        let (send_soc, recv_soc) = _create_zmq_socket_pair("test_connect", true).unwrap();
        let agent = Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || {
                sender.send(recv_soc.recv_string(0).unwrap().unwrap()).unwrap()
            }))
        };
        let agent_service = AgentService {
            agent: RefCell::new(Some(agent)),
        };
        let conn_handle = agent_service.connect("sd", "sk", "pk", "ep", "serv").unwrap();
        let expected_cmd = ConnectCmd {
            server_key: "serv".to_string(),
            public_key: "pk".to_string(),
            secret_key: "sk".to_string(),
            endpoint: "ep".to_string(),
            did: "sd".to_string(),
            conn_handle: conn_handle,
        };
        let str = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();
        assert_eq!(str, AgentWorkerCommand::Connect(expected_cmd).to_json().unwrap());
    }

    #[test]
    fn agent_worker_connect_works() {
        ::utils::logger::LoggerUtils::init();
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let ctx = zmq::Context::new();
        let recv_soc = ctx.socket(zmq::SocketType::ROUTER).unwrap();
        recv_soc.set_curve_publickey(recv_key_pair.public_key.as_str()).unwrap();
        recv_soc.set_curve_secretkey(recv_key_pair.secret_key.as_str()).unwrap();
        recv_soc.set_curve_server(true).unwrap();
        recv_soc.bind("tcp://127.0.0.1:*").unwrap();
        let addr = recv_soc.get_last_endpoint().unwrap().unwrap();
        info!("addr {}", addr);

        let mut agent_worker = AgentWorker {
            agent_connections: Vec::new(),
            cmd_socket: zmq::Context::new().socket(zmq::SocketType::PAIR).unwrap(),
        };
        let cmd = ConnectCmd {
            endpoint: addr,
            public_key: zmq::z85_decode(send_key_pair.public_key.as_str()).unwrap().to_base58(),
            secret_key: zmq::z85_decode(send_key_pair.secret_key.as_str()).unwrap().to_base58(),
            did: "".to_string(),
            server_key: zmq::z85_decode(recv_key_pair.public_key.as_str()).unwrap().to_base58(),
            conn_handle: 0,
        };

        agent_worker.connect(&cmd).unwrap();

        assert_eq!(agent_worker.agent_connections.len(), 1);
        recv_soc.recv_string(0).unwrap().unwrap(); //ignore identity
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn agent_worker_poll_works_for_cmd_socket() {
        let (send_soc, recv_soc) = _create_zmq_socket_pair("aw_poll_cmd", true).unwrap();
        let agent_worker = AgentWorker {
            agent_connections: Vec::new(),
            cmd_socket: recv_soc,
        };
        send_soc.send_str(r#"{"cmd": "Exit"}"#, zmq::DONTWAIT).unwrap();

        let cmds = agent_worker.poll().unwrap();

        assert_eq!(cmds.len(), 1);
        assert_match!(AgentWorkerCommand::Exit, cmds[0]);
    }

    #[test]
    fn agent_worker_poll_works_for_agent_socket() {
        let (send_soc, recv_soc) = _create_zmq_socket_pair("aw_poll_cmd", true).unwrap();
        let agent_worker = AgentWorker {
            agent_connections: vec!(RemoteAgent {
                socket: recv_soc,
                addr: String::new(),
                public_key: Vec::new(),
                secret_key: Vec::new(),
                server_key: Vec::new(),
                conn_handle: 0,
            }),
            cmd_socket: zmq::Context::new().socket(zmq::SocketType::PAIR).unwrap(),
        };
        send_soc.send_str("msg", zmq::DONTWAIT).unwrap();

        let mut cmds = agent_worker.poll().unwrap();

        assert_eq!(cmds.len(), 1);
        let cmd = cmds.remove(0);
        match cmd {
            AgentWorkerCommand::Response(resp) => {
                assert_eq!(resp.agent_ind, 0);
                assert_eq!(resp.msg, "msg");
            }
            _ => panic!("unexpected cmd {:?}", cmd),
        }
    }

    #[test]
    fn remote_agent_connect_works() {
        let dest = "test_agent_connect";
        let addr: String = format!("inproc://{}", dest);
        let (send_soc, recv_soc) = _create_zmq_socket_pair(dest, false).unwrap();
        recv_soc.bind(addr.as_str()).unwrap(); //TODO enable CurveCP
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let agent = RemoteAgent {
            socket: send_soc,
            addr: addr,
            server_key: zmq::z85_decode(send_key_pair.public_key.as_str()).unwrap(),
            secret_key: zmq::z85_decode(recv_key_pair.secret_key.as_str()).unwrap(),
            public_key: zmq::z85_decode(recv_key_pair.public_key.as_str()).unwrap(),
            conn_handle: 0,
        };
        agent.connect().unwrap();
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn agent_service_static_create_zmq_socket_pair_works() {
        let msg = "msg";
        let sockets = _create_zmq_socket_pair("test_pair", true).unwrap();
        sockets.0.send_str(msg, zmq::DONTWAIT).unwrap();
        assert_eq!(sockets.1.recv_string(zmq::DONTWAIT).unwrap().unwrap(), msg);
    }
}<commit_msg>Re-organize unit tests.<commit_after>#![warn(unused_variables)]
extern crate rust_base58;
extern crate serde_json;
extern crate zmq;

use self::rust_base58::FromBase58;
use std::cell::RefCell;
use std::thread;

use commands::{Command, CommandExecutor};
use commands::agent::AgentCommand;
use errors::common::CommonError;
use errors::pool::PoolError;
use utils::json::{JsonDecodable, JsonEncodable};
use utils::sequence::SequenceUtils;

struct RemoteAgent {
    socket: zmq::Socket,
    addr: String,
    public_key: Vec<u8>,
    secret_key: Vec<u8>,
    server_key: Vec<u8>,
    conn_handle: i32,
}

struct AgentWorker {
    cmd_socket: zmq::Socket,
    agent_connections: Vec<RemoteAgent>,
}

struct Agent {
    cmd_socket: zmq::Socket,
    worker: Option<thread::JoinHandle<()>>,
}

impl Drop for Agent {
    fn drop(&mut self) {
        trace!("agent drop >>");
        self.cmd_socket.send_str(AgentWorkerCommand::Exit.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap(); //TODO
        self.worker.take().unwrap().join().unwrap();
        trace!("agent drop <<");
    }
}

pub struct AgentService {
    agent: RefCell<Option<Agent>>,
}

impl Agent {
    pub fn new() -> Agent {
        let (send_soc, recv_soc) = _create_zmq_socket_pair("agent", true).unwrap();
        let mut worker = AgentWorker {
            cmd_socket: recv_soc,
            agent_connections: Vec::new(),
        };
        Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || { worker.run() }))
        }
    }
}

impl AgentService {
    pub fn new() -> AgentService {
        AgentService { agent: RefCell::new((None)) }
    }

    pub fn connect(&self, sender_did: &str, my_sk: &str, my_pk: &str, endpoint: &str, server_key: &str) -> Result<i32, CommonError> {
        let mut agent = self.agent.borrow_mut();
        if agent.is_none() {
            *agent = Some(Agent::new());
        }
        let conn_handle = SequenceUtils::get_next_id();
        let connect_cmd: AgentWorkerCommand = AgentWorkerCommand::Connect(ConnectCmd {
            did: sender_did.to_string(),
            secret_key: my_sk.to_string(),
            public_key: my_pk.to_string(),
            endpoint: endpoint.to_string(),
            server_key: server_key.to_string(),
            conn_handle: conn_handle,
        });
        agent.as_ref().unwrap().cmd_socket.send_str(connect_cmd.to_json().unwrap().as_str(), zmq::DONTWAIT).unwrap();
        Ok(conn_handle)
    }
}

impl AgentWorker {
    fn run(&mut self) {
        'agent_pool_loop: loop {
            trace!("agent worker poll loop >>");
            let cmds = self.poll().unwrap();
            for cmd in cmds {
                info!("received cmd {:?}", cmd);
                match cmd {
                    AgentWorkerCommand::Connect(cmd) => self.connect(&cmd).unwrap(),
                    AgentWorkerCommand::Response(resp) => self.agent_connections[resp.agent_ind].handle_response(resp.msg),
                    AgentWorkerCommand::Exit => break 'agent_pool_loop,
                }
            }
            trace!("agent worker poll loop <<");
        }
        trace!("agent poll finished");
    }

    fn connect(&mut self, cmd: &ConnectCmd) -> Result<(), PoolError> {
        let ra = RemoteAgent::new(cmd.public_key.as_str(), cmd.secret_key.as_str(),
                                  cmd.server_key.as_str(), cmd.endpoint.as_str(),
                                  cmd.conn_handle)
            .map_err(map_err_trace!("RemoteAgent::new failed"))?;
        ra.connect().map_err(map_err_trace!("RemoteAgent::connect failed"))?;
        self.agent_connections.push(ra);
        Ok(())
    }

    fn poll(&self) -> Result<Vec<AgentWorkerCommand>, zmq::Error> {
        let mut result = Vec::new();
        let mut poll_items: Vec<zmq::PollItem> = Vec::new();
        poll_items.push(self.cmd_socket.as_poll_item(zmq::POLLIN));

        for agent_conn in &self.agent_connections {
            poll_items.push(agent_conn.socket.as_poll_item(zmq::POLLIN));
        }

        zmq::poll(poll_items.as_mut_slice(), -1).map_err(map_err_trace!("agent poll failed"))?;

        if poll_items[0].is_readable() {
            let msg = self.cmd_socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
            info!("Input on cmd socket {}", msg);
            result.push(AgentWorkerCommand::from_json(msg.as_str()).unwrap());
        }

        for i in 0..self.agent_connections.len() {
            if poll_items[1 + i].is_readable() {
                let msg = self.agent_connections[i].socket.recv_string(zmq::DONTWAIT).unwrap().unwrap();
                info!("Input on agent socket {}: {}", i, msg);
                result.push(AgentWorkerCommand::Response(Response {
                    agent_ind: i,
                    msg: msg,
                }))
            }
        }

        Ok(result)
    }
}

impl RemoteAgent {
    fn new(pub_key: &str, sec_key: &str, ver_key: &str, addr: &str, conn_handle: i32) -> Result<RemoteAgent, PoolError> {
        Ok(RemoteAgent {
            socket: zmq::Context::new().socket(zmq::SocketType::DEALER)?,
            public_key: pub_key.from_base58()
                .map_err(|err| PoolError::CommonError(CommonError::InvalidStructure(format!("invalid pub_key {}", err))))?,
            secret_key: sec_key.from_base58()
                .map_err(|err| PoolError::CommonError(CommonError::InvalidStructure(format!("invalid sec_key {}", err))))?,
            server_key: ver_key.from_base58()
                .map_err(|err| PoolError::CommonError(CommonError::InvalidStructure(format!("invalid server_key {}", err))))?,
            addr: addr.to_string(),
            conn_handle: conn_handle,
        })
    }

    fn connect(&self) -> Result<(), PoolError> {
        impl From<zmq::EncodeError> for PoolError {
            fn from(err: zmq::EncodeError) -> PoolError {
                PoolError::CommonError(CommonError::InvalidState(format!("Invalid data stored RemoteAgent detected while connect {:?}", err)))
            }
        }
        self.socket.set_identity(zmq::z85_encode(self.public_key.as_slice())?.as_bytes())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_secretkey(zmq::z85_encode(self.secret_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_publickey(zmq::z85_encode(self.public_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_curve_serverkey(zmq::z85_encode(self.server_key.as_slice())?.as_str())
            .map_err(map_err_trace!())?;
        self.socket.set_linger(0).map_err(map_err_trace!())?; //TODO set correct timeout
        self.socket.connect(self.addr.as_str())
            .map_err(map_err_trace!("RemoteAgent::connect self.socket.connect failed"))?;
        self.socket.send_str("DID", zmq::DONTWAIT).map_err(map_err_trace!())?;
        Ok(())
    }

    fn handle_response(&self, msg: String) {
        if msg.eq("DID_ACK") {
            let send_res: Result<(), CommonError> =
                CommandExecutor::instance().send(
                    Command::Agent(
                        AgentCommand::ConnectAck(self.conn_handle, Ok(self.conn_handle))));
            if let Err(err) = send_res {
                error!("RemoteAgent::handle_response got connection ack, but can't send to client {}", err);
            };
        } else {
            //check state, transfer message to client
            unimplemented!();
        }
    }
}

#[serde(tag = "cmd")]
#[derive(Serialize, Deserialize, Debug)]
enum AgentWorkerCommand {
    Connect(ConnectCmd),
    Response(Response),
    Exit,
}

impl JsonEncodable for AgentWorkerCommand {}

impl<'a> JsonDecodable<'a> for AgentWorkerCommand {}

#[derive(Serialize, Deserialize, Debug)]
struct ConnectCmd {
    endpoint: String,
    did: String,
    secret_key: String,
    public_key: String,
    server_key: String,
    conn_handle: i32,
}

#[derive(Serialize, Deserialize, Debug)]
struct Response {
    agent_ind: usize,
    msg: String,
}

fn _create_zmq_socket_pair(address: &str, connect_and_bind: bool) -> Result<(zmq::Socket, zmq::Socket), zmq::Error> {
    let ctx = zmq::Context::new();
    let recv_soc = ctx.socket(zmq::SocketType::PAIR)?;
    let send_soc = ctx.socket(zmq::SocketType::PAIR)?;
    if connect_and_bind {
        let address = format!("inproc://{}", address);
        recv_soc.bind(&address)?;
        send_soc.connect(&address)?;
    }
    Ok((send_soc, recv_soc))
}

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

    use std::sync::mpsc::channel;
    use super::rust_base58::ToBase58;

    use utils::timeout::TimeoutUtils;

    #[test]
    fn agent_can_be_dropped() {
        let (sender, receiver) = channel();
        thread::spawn(move || {
            #[allow(unused_variables)]
            {
                let agent = Agent::new();
            }
            sender.send(true).unwrap();
        });
        receiver.recv_timeout(TimeoutUtils::short_timeout()).expect("drop not finished");
    }

    #[test]
    fn agent_service_connect_works() {
        let (sender, receiver) = channel();
        let (send_soc, recv_soc) = _create_zmq_socket_pair("test_connect", true).unwrap();
        let agent = Agent {
            cmd_socket: send_soc,
            worker: Some(thread::spawn(move || {
                sender.send(recv_soc.recv_string(0).unwrap().unwrap()).unwrap()
            }))
        };
        let agent_service = AgentService {
            agent: RefCell::new(Some(agent)),
        };
        let conn_handle = agent_service.connect("sd", "sk", "pk", "ep", "serv").unwrap();
        let expected_cmd = ConnectCmd {
            server_key: "serv".to_string(),
            public_key: "pk".to_string(),
            secret_key: "sk".to_string(),
            endpoint: "ep".to_string(),
            did: "sd".to_string(),
            conn_handle: conn_handle,
        };
        let str = receiver.recv_timeout(TimeoutUtils::short_timeout()).unwrap();
        assert_eq!(str, AgentWorkerCommand::Connect(expected_cmd).to_json().unwrap());
    }

    mod agent_worker {
        use super::*;

        #[test]
        fn agent_worker_connect_works() {
            ::utils::logger::LoggerUtils::init();
            let send_key_pair = zmq::CurveKeyPair::new().unwrap();
            let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
            let ctx = zmq::Context::new();
            let recv_soc = ctx.socket(zmq::SocketType::ROUTER).unwrap();
            recv_soc.set_curve_publickey(recv_key_pair.public_key.as_str()).unwrap();
            recv_soc.set_curve_secretkey(recv_key_pair.secret_key.as_str()).unwrap();
            recv_soc.set_curve_server(true).unwrap();
            recv_soc.bind("tcp://127.0.0.1:*").unwrap();
            let addr = recv_soc.get_last_endpoint().unwrap().unwrap();
            info!("addr {}", addr);

            let mut agent_worker = AgentWorker {
                agent_connections: Vec::new(),
                cmd_socket: zmq::Context::new().socket(zmq::SocketType::PAIR).unwrap(),
            };
            let cmd = ConnectCmd {
                endpoint: addr,
                public_key: zmq::z85_decode(send_key_pair.public_key.as_str()).unwrap().to_base58(),
                secret_key: zmq::z85_decode(send_key_pair.secret_key.as_str()).unwrap().to_base58(),
                did: "".to_string(),
                server_key: zmq::z85_decode(recv_key_pair.public_key.as_str()).unwrap().to_base58(),
                conn_handle: 0,
            };

            agent_worker.connect(&cmd).unwrap();

            assert_eq!(agent_worker.agent_connections.len(), 1);
            recv_soc.recv_string(0).unwrap().unwrap(); //ignore identity
            assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
        }

        #[test]
        fn agent_worker_poll_works_for_cmd_socket() {
            let (send_soc, recv_soc) = _create_zmq_socket_pair("aw_poll_cmd", true).unwrap();
            let agent_worker = AgentWorker {
                agent_connections: Vec::new(),
                cmd_socket: recv_soc,
            };
            send_soc.send_str(r#"{"cmd": "Exit"}"#, zmq::DONTWAIT).unwrap();

            let cmds = agent_worker.poll().unwrap();

            assert_eq!(cmds.len(), 1);
            assert_match!(AgentWorkerCommand::Exit, cmds[0]);
        }

        #[test]
        fn agent_worker_poll_works_for_agent_socket() {
            let (send_soc, recv_soc) = _create_zmq_socket_pair("aw_poll_cmd", true).unwrap();
            let agent_worker = AgentWorker {
                agent_connections: vec!(RemoteAgent {
                    socket: recv_soc,
                    addr: String::new(),
                    public_key: Vec::new(),
                    secret_key: Vec::new(),
                    server_key: Vec::new(),
                    conn_handle: 0,
                }),
                cmd_socket: zmq::Context::new().socket(zmq::SocketType::PAIR).unwrap(),
            };
            send_soc.send_str("msg", zmq::DONTWAIT).unwrap();

            let mut cmds = agent_worker.poll().unwrap();

            assert_eq!(cmds.len(), 1);
            let cmd = cmds.remove(0);
            match cmd {
                AgentWorkerCommand::Response(resp) => {
                    assert_eq!(resp.agent_ind, 0);
                    assert_eq!(resp.msg, "msg");
                }
                _ => panic!("unexpected cmd {:?}", cmd),
            }
        }
    }

    #[test]
    fn remote_agent_connect_works() {
        let dest = "test_agent_connect";
        let addr: String = format!("inproc://{}", dest);
        let (send_soc, recv_soc) = _create_zmq_socket_pair(dest, false).unwrap();
        recv_soc.bind(addr.as_str()).unwrap(); //TODO enable CurveCP
        let send_key_pair = zmq::CurveKeyPair::new().unwrap();
        let recv_key_pair = zmq::CurveKeyPair::new().unwrap();
        let agent = RemoteAgent {
            socket: send_soc,
            addr: addr,
            server_key: zmq::z85_decode(send_key_pair.public_key.as_str()).unwrap(),
            secret_key: zmq::z85_decode(recv_key_pair.secret_key.as_str()).unwrap(),
            public_key: zmq::z85_decode(recv_key_pair.public_key.as_str()).unwrap(),
            conn_handle: 0,
        };
        agent.connect().unwrap();
        assert_eq!(recv_soc.recv_string(zmq::DONTWAIT).unwrap().unwrap(), "DID");
    }

    #[test]
    fn agent_service_static_create_zmq_socket_pair_works() {
        let msg = "msg";
        let sockets = _create_zmq_socket_pair("test_pair", true).unwrap();
        sockets.0.send_str(msg, zmq::DONTWAIT).unwrap();
        assert_eq!(sockets.1.recv_string(zmq::DONTWAIT).unwrap().unwrap(), msg);
    }
}<|endoftext|>


<commit_before>//! Runtime support needed for the `#![assert_instr]` macro
//!
//! This basically just disassembles the current executable and then parses the
//! output once globally and then provides the `assert` function which makes
//! assertions about the disassembly of a function.

#![feature(proc_macro)]

extern crate assert_instr_macro;
extern crate backtrace;
extern crate cc;
extern crate rustc_demangle;
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;
use std::env;
use std::process::Command;
use std::str;

pub use assert_instr_macro::*;

lazy_static! {
    static ref DISASSEMBLY: HashMap<String, Vec<Function>> = disassemble_myself();
}

struct Function {
    instrs: Vec<Instruction>,
}

struct Instruction {
    parts: Vec<String>,
}

fn disassemble_myself() -> HashMap<String, Vec<Function>> {
    let me = env::current_exe().expect("failed to get current exe");

    if cfg!(target_arch = "x86_64") &&
        cfg!(target_os = "windows") &&
        cfg!(target_env = "msvc") {
        let mut cmd = cc::windows_registry::find("x86_64-pc-windows-msvc", "dumpbin.exe")
            .expect("failed to find `dumpbin` tool");
        let output = cmd.arg("/DISASM").arg(&me).output()
            .expect("failed to execute dumpbin");
        println!("{}\n{}", output.status, String::from_utf8_lossy(&output.stderr));
        assert!(output.status.success());
        parse_dumpbin(&String::from_utf8_lossy(&output.stdout))
    } else if cfg!(target_os = "windows") {
        panic!("disassembly unimplemented")
    } else if cfg!(target_os = "macos") {
        let output = Command::new("otool")
            .arg("-vt")
            .arg(&me)
            .output()
            .expect("failed to execute otool");
        println!("{}\n{}", output.status, String::from_utf8_lossy(&output.stderr));
        assert!(output.status.success());

        parse_otool(&str::from_utf8(&output.stdout).expect("stdout not utf8"))
    } else {
        let output = Command::new("objdump")
            .arg("--disassemble")
            .arg(&me)
            .output()
            .expect("failed to execute objdump");
        println!("{}\n{}", output.status, String::from_utf8_lossy(&output.stderr));
        assert!(output.status.success());

        parse_objdump(&str::from_utf8(&output.stdout).expect("stdout not utf8"))
    }
}

fn parse_objdump(output: &str) -> HashMap<String, Vec<Function>> {
    let mut lines = output.lines();

    for line in output.lines().take(100) {
        println!("{}", line);
    }

    let mut ret = HashMap::new();
    while let Some(header) = lines.next() {
        // symbols should start with `$hex_addr <$name>:`
        if !header.ends_with(">:") {
            continue
        }
        let start = header.find("<").unwrap();
        let symbol = &header[start + 1..header.len() - 2];

        let mut instructions = Vec::new();
        while let Some(instruction) = lines.next() {
            if instruction.is_empty() {
                break
            }
            // Each line of instructions should look like:
            //
            //      $rel_offset: ab cd ef 00    $instruction...
            let parts = instruction.split_whitespace()
                .skip(1)
                .skip_while(|s| {
                    s.len() == 2 && usize::from_str_radix(s, 16).is_ok()
                })
                .map(|s| s.to_string())
                .collect::<Vec<String>>();
            instructions.push(Instruction { parts });
        }

        ret.entry(normalize(symbol))
            .or_insert(Vec::new())
            .push(Function { instrs: instructions });
    }

    return ret
}

fn parse_otool(output: &str) -> HashMap<String, Vec<Function>> {
    let mut lines = output.lines();

    for line in output.lines().take(100) {
        println!("{}", line);
    }

    let mut ret = HashMap::new();
    let mut cached_header = None;
    loop {
        let header = match cached_header.take().or_else(|| lines.next()) {
            Some(header) => header,
            None => break,
        };
        // symbols should start with `$symbol:`
        if !header.ends_with(":") {
            continue
        }
        // strip the leading underscore and the trailing colon
        let symbol = &header[1..header.len() - 1];

        let mut instructions = Vec::new();
        while let Some(instruction) = lines.next() {
            if instruction.ends_with(":") {
                cached_header = Some(instruction);
                break
            }
            // Each line of instructions should look like:
            //
            //      $addr    $instruction...
            let parts = instruction.split_whitespace()
                .skip(1)
                .map(|s| s.to_string())
                .collect::<Vec<String>>();
            instructions.push(Instruction { parts });
        }

        ret.entry(normalize(symbol))
            .or_insert(Vec::new())
            .push(Function { instrs: instructions });
    }

    return ret
}

fn parse_dumpbin(output: &str) -> HashMap<String, Vec<Function>> {
    let mut lines = output.lines();

    for line in output.lines().take(100) {
        println!("{}", line);
    }

    let mut ret = HashMap::new();
    let mut cached_header = None;
    loop {
        let header = match cached_header.take().or_else(|| lines.next()) {
            Some(header) => header,
            None => break,
        };
        // symbols should start with `$symbol:`
        if !header.ends_with(":") {
            continue
        }
        // strip the trailing colon
        let symbol = &header[..header.len() - 1];

        let mut instructions = Vec::new();
        while let Some(instruction) = lines.next() {
            if !instruction.starts_with("  ") {
                cached_header = Some(instruction);
                break
            }
            // Each line looks like:
            //
            // >  $addr: ab cd ef     $instr..
            // >         00 12          # this line os optional
            if instruction.starts_with("       ") {
                continue
            }
            let parts = instruction.split_whitespace()
                .skip(1)
                .skip_while(|s| {
                    s.len() == 2 && usize::from_str_radix(s, 16).is_ok()
                })
                .map(|s| s.to_string())
                .collect::<Vec<String>>();
            instructions.push(Instruction { parts });
        }

        ret.entry(normalize(symbol))
            .or_insert(Vec::new())
            .push(Function { instrs: instructions });
    }

    return ret
}

fn normalize(symbol: &str) -> String {
    let symbol = rustc_demangle::demangle(symbol).to_string();
    match symbol.rfind("::h") {
        Some(i) => symbol[..i].to_string(),
        None => symbol.to_string(),
    }
}

/// Main entry point for this crate, called by the `#[assert_instr]` macro.
///
/// This asserts that the function at `fnptr` contains the instruction
/// `expected` provided.
pub fn assert(fnptr: usize, expected: &str) {
    // Translate this function pointer to a symbolic name that we'd have found
    // in the disassembly.
    let mut sym = None;
    backtrace::resolve(fnptr as *mut _, |name| {
        sym = name.name().and_then(|s| s.as_str()).map(normalize);
    });
    let sym = match sym {
        Some(s) => s,
        None => panic!("failed to get symbol of function pointer: {}", fnptr),
    };

    // Find our function in the list of all disassembled functions
    let functions = &DISASSEMBLY.get(&sym)
        .expect(&format!("failed to find disassembly of {}", sym));
    assert_eq!(functions.len(), 1);
    let function = &functions[0];

    // Look for `expected` as the first part of any instruction in this
    // function, returning if we do indeed find it.
    for instr in function.instrs.iter() {
        if let Some(part) = instr.parts.get(0) {
            if part == expected {
                return
            }
        }
    }

    // Help debug by printing out the found disassembly, and then panic as we
    // didn't find the instruction.
    println!("disassembly for {}: ", sym);
    for (i, instr) in function.instrs.iter().enumerate() {
        print!("\t{:2}: ", i);
        for part in instr.parts.iter() {
            print!("{} ", part);
        }
        println!("");
    }
    panic!("failed to find instruction `{}` in the disassembly", expected);
}

<commit_msg>[assert-instr] compare only the instruction prefix<commit_after>//! Runtime support needed for the `#![assert_instr]` macro
//!
//! This basically just disassembles the current executable and then parses the
//! output once globally and then provides the `assert` function which makes
//! assertions about the disassembly of a function.

#![feature(proc_macro)]

extern crate assert_instr_macro;
extern crate backtrace;
extern crate cc;
extern crate rustc_demangle;
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;
use std::env;
use std::process::Command;
use std::str;

pub use assert_instr_macro::*;

lazy_static! {
    static ref DISASSEMBLY: HashMap<String, Vec<Function>> = disassemble_myself();
}

struct Function {
    instrs: Vec<Instruction>,
}

struct Instruction {
    parts: Vec<String>,
}

fn disassemble_myself() -> HashMap<String, Vec<Function>> {
    let me = env::current_exe().expect("failed to get current exe");

    if cfg!(target_arch = "x86_64") &&
        cfg!(target_os = "windows") &&
        cfg!(target_env = "msvc") {
        let mut cmd = cc::windows_registry::find("x86_64-pc-windows-msvc", "dumpbin.exe")
            .expect("failed to find `dumpbin` tool");
        let output = cmd.arg("/DISASM").arg(&me).output()
            .expect("failed to execute dumpbin");
        println!("{}\n{}", output.status, String::from_utf8_lossy(&output.stderr));
        assert!(output.status.success());
        parse_dumpbin(&String::from_utf8_lossy(&output.stdout))
    } else if cfg!(target_os = "windows") {
        panic!("disassembly unimplemented")
    } else if cfg!(target_os = "macos") {
        let output = Command::new("otool")
            .arg("-vt")
            .arg(&me)
            .output()
            .expect("failed to execute otool");
        println!("{}\n{}", output.status, String::from_utf8_lossy(&output.stderr));
        assert!(output.status.success());

        parse_otool(&str::from_utf8(&output.stdout).expect("stdout not utf8"))
    } else {
        let output = Command::new("objdump")
            .arg("--disassemble")
            .arg(&me)
            .output()
            .expect("failed to execute objdump");
        println!("{}\n{}", output.status, String::from_utf8_lossy(&output.stderr));
        assert!(output.status.success());

        parse_objdump(&str::from_utf8(&output.stdout).expect("stdout not utf8"))
    }
}

fn parse_objdump(output: &str) -> HashMap<String, Vec<Function>> {
    let mut lines = output.lines();

    for line in output.lines().take(100) {
        println!("{}", line);
    }

    let mut ret = HashMap::new();
    while let Some(header) = lines.next() {
        // symbols should start with `$hex_addr <$name>:`
        if !header.ends_with(">:") {
            continue
        }
        let start = header.find("<").unwrap();
        let symbol = &header[start + 1..header.len() - 2];

        let mut instructions = Vec::new();
        while let Some(instruction) = lines.next() {
            if instruction.is_empty() {
                break
            }
            // Each line of instructions should look like:
            //
            //      $rel_offset: ab cd ef 00    $instruction...
            let parts = instruction.split_whitespace()
                .skip(1)
                .skip_while(|s| {
                    s.len() == 2 && usize::from_str_radix(s, 16).is_ok()
                })
                .map(|s| s.to_string())
                .collect::<Vec<String>>();
            instructions.push(Instruction { parts });
        }

        ret.entry(normalize(symbol))
            .or_insert(Vec::new())
            .push(Function { instrs: instructions });
    }

    return ret
}

fn parse_otool(output: &str) -> HashMap<String, Vec<Function>> {
    let mut lines = output.lines();

    for line in output.lines().take(100) {
        println!("{}", line);
    }

    let mut ret = HashMap::new();
    let mut cached_header = None;
    loop {
        let header = match cached_header.take().or_else(|| lines.next()) {
            Some(header) => header,
            None => break,
        };
        // symbols should start with `$symbol:`
        if !header.ends_with(":") {
            continue
        }
        // strip the leading underscore and the trailing colon
        let symbol = &header[1..header.len() - 1];

        let mut instructions = Vec::new();
        while let Some(instruction) = lines.next() {
            if instruction.ends_with(":") {
                cached_header = Some(instruction);
                break
            }
            // Each line of instructions should look like:
            //
            //      $addr    $instruction...
            let parts = instruction.split_whitespace()
                .skip(1)
                .map(|s| s.to_string())
                .collect::<Vec<String>>();
            instructions.push(Instruction { parts });
        }

        ret.entry(normalize(symbol))
            .or_insert(Vec::new())
            .push(Function { instrs: instructions });
    }

    return ret
}

fn parse_dumpbin(output: &str) -> HashMap<String, Vec<Function>> {
    let mut lines = output.lines();

    for line in output.lines().take(100) {
        println!("{}", line);
    }

    let mut ret = HashMap::new();
    let mut cached_header = None;
    loop {
        let header = match cached_header.take().or_else(|| lines.next()) {
            Some(header) => header,
            None => break,
        };
        // symbols should start with `$symbol:`
        if !header.ends_with(":") {
            continue
        }
        // strip the trailing colon
        let symbol = &header[..header.len() - 1];

        let mut instructions = Vec::new();
        while let Some(instruction) = lines.next() {
            if !instruction.starts_with("  ") {
                cached_header = Some(instruction);
                break
            }
            // Each line looks like:
            //
            // >  $addr: ab cd ef     $instr..
            // >         00 12          # this line os optional
            if instruction.starts_with("       ") {
                continue
            }
            let parts = instruction.split_whitespace()
                .skip(1)
                .skip_while(|s| {
                    s.len() == 2 && usize::from_str_radix(s, 16).is_ok()
                })
                .map(|s| s.to_string())
                .collect::<Vec<String>>();
            instructions.push(Instruction { parts });
        }

        ret.entry(normalize(symbol))
            .or_insert(Vec::new())
            .push(Function { instrs: instructions });
    }

    return ret
}

fn normalize(symbol: &str) -> String {
    let symbol = rustc_demangle::demangle(symbol).to_string();
    match symbol.rfind("::h") {
        Some(i) => symbol[..i].to_string(),
        None => symbol.to_string(),
    }
}

/// Main entry point for this crate, called by the `#[assert_instr]` macro.
///
/// This asserts that the function at `fnptr` contains the instruction
/// `expected` provided.
pub fn assert(fnptr: usize, expected: &str) {
    // Translate this function pointer to a symbolic name that we'd have found
    // in the disassembly.
    let mut sym = None;
    backtrace::resolve(fnptr as *mut _, |name| {
        sym = name.name().and_then(|s| s.as_str()).map(normalize);
    });
    let sym = match sym {
        Some(s) => s,
        None => panic!("failed to get symbol of function pointer: {}", fnptr),
    };

    // Find our function in the list of all disassembled functions
    let functions = &DISASSEMBLY.get(&sym)
        .expect(&format!("failed to find disassembly of {}", sym));
    assert_eq!(functions.len(), 1);
    let function = &functions[0];

    // Look for `expected` as the first part of any instruction in this
    // function, returning if we do indeed find it.
    for instr in function.instrs.iter() {
        // Gets the first instruction, e.g. tzcntl in tzcntl %rax,%rax
        if let Some(part) = instr.parts.get(0) {
            // Truncates the instruction with the length of the expected
            // instruction: tzcntl => tzcnt and compares that.
            if let Some(part) = part.get(0..expected.len()) {
                if part == expected {
                    return
                }
            }
        }
    }

    // Help debug by printing out the found disassembly, and then panic as we
    // didn't find the instruction.
    println!("disassembly for {}: ", sym);
    for (i, instr) in function.instrs.iter().enumerate() {
        print!("\t{:2}: ", i);
        for part in instr.parts.iter() {
            print!("{} ", part);
        }
        println!("");
    }
    panic!("failed to find instruction `{}` in the disassembly", expected);
}

<|endoftext|>


<commit_before>use crate::tests;
use crate::*;
use cgmath::Point2;

// use std::path;

#[test]
fn image_encode() {
    let (c, _e) = &mut tests::make_context();
    let image = graphics::Image::new(c, "/player.png").unwrap();
    image
        .encode(c, graphics::ImageFormat::Png, "/encode_test.png")
        .unwrap();
}

fn get_rgba_sample(rgba_buf: &[u8], width: usize, sample_pos: (usize, usize)) -> (u8, u8, u8, u8) {
    (
        rgba_buf[(width * sample_pos.1 + sample_pos.0) * 4 + 0],
        rgba_buf[(width * sample_pos.1 + sample_pos.0) * 4 + 1],
        rgba_buf[(width * sample_pos.1 + sample_pos.0) * 4 + 2],
        rgba_buf[(width * sample_pos.1 + sample_pos.0) * 4 + 3],
    )
}

#[test]
fn save_screenshot() {
    let (c, _e) = &mut tests::make_context();
    graphics::clear(c, graphics::Color::new(0.1, 0.2, 0.3, 1.0));

    let width = graphics::drawable_size(c).0;
    let height = graphics::drawable_size(c).1;

    let color_topleft = graphics::WHITE;
    let color_topright = graphics::Color::new(1.0, 0.0, 0.0, 1.0);
    let color_bottomleft = graphics::Color::new(0.0, 1.0, 0.0, 1.0);
    let color_bottomright = graphics::Color::new(0.0, 0.0, 1.0, 1.0);

    let rect = graphics::Mesh::new_rectangle(
        c,
        graphics::DrawMode::fill(),
        graphics::types::Rect {
            x: 0.0,
            y: 0.0,
            w: width / 2.0,
            h: height / 2.0,
        },
        graphics::WHITE,
    )
    .unwrap();

    graphics::draw(c, &rect, graphics::DrawParam::new().color(color_topleft)).unwrap();
    graphics::draw(
        c,
        &rect,
        graphics::DrawParam::new()
            .color(color_topright)
            .dest(Point2::new(width / 2.0, 0.0)),
    )
    .unwrap();
    graphics::draw(
        c,
        &rect,
        graphics::DrawParam::new()
            .color(color_bottomleft)
            .dest(Point2::new(0.0, height / 2.0)),
    )
    .unwrap();
    graphics::draw(
        c,
        &rect,
        graphics::DrawParam::new()
            .color(color_bottomright)
            .dest(Point2::new(width / 2.0, height / 2.0)),
    )
    .unwrap();

    // Don't do graphics::present(c) since calling it once (!) would mean that the result of our draw operation
    // went to the front buffer and the active screen texture is actually empty.
    c.gfx_context.encoder.flush(&mut *c.gfx_context.device);

    let screenshot = graphics::screenshot(c).unwrap();

    // Check if screenshot has right general properties
    assert_eq!(width as u16, screenshot.width);
    assert_eq!(height as u16, screenshot.height);
    assert_eq!(None, screenshot.blend_mode);

    // Image comparision or rendered output is hard, but we *know* that top left should be white.
    // So take a samples in the middle of each rectangle we drew and compare.
    // Note that we only use fully saturated colors to avoid any issues with color spaces.
    let rgba_buf = screenshot.to_rgba8(c).unwrap();
    let width = screenshot.width as usize;
    let quarter_size = (
        screenshot.width as usize / 4,
        screenshot.height as usize / 4,
    );
    assert_eq!(
        color_topleft.to_rgba(),
        get_rgba_sample(&rgba_buf, width, (quarter_size.0, quarter_size.1))
    );
    assert_eq!(
        color_topright.to_rgba(),
        get_rgba_sample(&rgba_buf, width, (quarter_size.0 * 3, quarter_size.1))
    );
    assert_eq!(
        color_bottomleft.to_rgba(),
        get_rgba_sample(&rgba_buf, width, (quarter_size.0, quarter_size.1 * 3))
    );
    assert_eq!(
        color_bottomright.to_rgba(),
        get_rgba_sample(&rgba_buf, width, (quarter_size.0 * 3, quarter_size.1 * 3))
    );

    // save screenshot (no check, just to see if it doesn't crash)
    screenshot
        .encode(c, graphics::ImageFormat::Png, "/screenshot_test.png")
        .unwrap();
}

#[test]
fn load_images() {
    let (c, _e) = &mut tests::make_context();
    let image = graphics::Image::new(c, "/player.png").unwrap();
    image
        .encode(c, graphics::ImageFormat::Png, "/player_save_test.png")
        .unwrap();
    let _i2 = graphics::Image::new(c, "/player_save_test.png").unwrap();
}

#[test]
fn sanity_check_window_sizes() {
    let (c, e) = &mut tests::make_context();

    // Make sure that window sizes are what we ask for, and not what hidpi gives us.
    let w = c.conf.window_mode.width;
    let h = c.conf.window_mode.height;
    let size = graphics::drawable_size(c);
    assert_eq!(w, size.0);
    assert_eq!(h, size.1);

    let outer_size = graphics::size(c);
    assert!(size.0 <= outer_size.0);
    assert!(size.1 <= outer_size.1);

    // Make sure resizing the window works.
    let w = 100.0;
    let h = 200.0;
    graphics::set_drawable_size(c, w, h).unwrap();
    // ahahaha this apparently REQUIRES a delay between setting
    // the size and it actually altering, at least on Linux X11
    std::thread::sleep(std::time::Duration::from_millis(100));
    // Maybe we need to run the event pump too?  It seems VERY flaky.
    // Sometimes you need one, sometimes you need both...
    e.poll_events(|event| {
        c.process_event(&event);
    });

    let size = graphics::drawable_size(c);
    assert_eq!(w, size.0);
    assert_eq!(h, size.1);
}

/// Ensure that the transform stack applies operations in the correct order.
#[test]
fn test_transform_stack_order() {
    let (ctx, _e) = &mut tests::make_context();
    let p1 = graphics::DrawParam::default();
    let p2 = graphics::DrawParam::default();
    let t1 = p1.to_matrix();
    let t2 = p2.to_matrix();
    graphics::push_transform(ctx, Some(t1));
    graphics::mul_transform(ctx, t2);
    let res = crate::nalgebra::Matrix4::<f32>::from(graphics::transform(ctx));
    let m1: crate::nalgebra::Matrix4<f32> = t1.into();
    let m2: crate::nalgebra::Matrix4<f32> = t2.into();
    assert_eq!(res, m2 * m1);
}
<commit_msg>shortened screenshot test code<commit_after>use crate::graphics::Color;
use crate::tests;
use crate::*;
use cgmath::Point2;

// use std::path;

#[test]
fn image_encode() {
    let (c, _e) = &mut tests::make_context();
    let image = graphics::Image::new(c, "/player.png").unwrap();
    image
        .encode(c, graphics::ImageFormat::Png, "/encode_test.png")
        .unwrap();
}

fn get_rgba_sample(rgba_buf: &[u8], width: usize, sample_pos: Point2<f32>) -> (u8, u8, u8, u8) {
    (
        rgba_buf[(width * sample_pos.y as usize + sample_pos.x as usize) * 4 + 0],
        rgba_buf[(width * sample_pos.y as usize + sample_pos.x as usize) * 4 + 1],
        rgba_buf[(width * sample_pos.y as usize + sample_pos.x as usize) * 4 + 2],
        rgba_buf[(width * sample_pos.y as usize + sample_pos.x as usize) * 4 + 3],
    )
}

#[test]
fn save_screenshot() {
    let (c, _e) = &mut tests::make_context();
    graphics::clear(c, Color::new(0.1, 0.2, 0.3, 1.0));

    let width = graphics::drawable_size(c).0;
    let height = graphics::drawable_size(c).1;

    let topleft = graphics::DrawParam::new()
        .color(graphics::WHITE)
        .dest(Point2::new(0.0, 0.0));
    let topright = graphics::DrawParam::new()
        .color(Color::new(1.0, 0.0, 0.0, 1.0))
        .dest(Point2::new(width / 2.0, 0.0));
    let bottomleft = graphics::DrawParam::new()
        .color(Color::new(0.0, 1.0, 0.0, 1.0))
        .dest(Point2::new(0.0, height / 2.0));
    let bottomright = graphics::DrawParam::new()
        .color(Color::new(0.0, 0.0, 1.0, 1.0))
        .dest(Point2::new(width / 2.0, height / 2.0));

    let rect = graphics::Mesh::new_rectangle(
        c,
        graphics::DrawMode::fill(),
        graphics::types::Rect {
            x: 0.0,
            y: 0.0,
            w: width / 2.0,
            h: height / 2.0,
        },
        graphics::WHITE,
    )
    .unwrap();

    graphics::draw(c, &rect, topleft).unwrap();
    graphics::draw(c, &rect, topright).unwrap();
    graphics::draw(c, &rect, bottomleft).unwrap();
    graphics::draw(c, &rect, bottomright).unwrap();

    // Don't do graphics::present(c) since calling it once (!) would mean that the result of our draw operation
    // went to the front buffer and the active screen texture is actually empty.
    c.gfx_context.encoder.flush(&mut *c.gfx_context.device);

    let screenshot = graphics::screenshot(c).unwrap();

    // Check if screenshot has right general properties
    assert_eq!(width as u16, screenshot.width);
    assert_eq!(height as u16, screenshot.height);
    assert_eq!(None, screenshot.blend_mode);

    // Image comparision or rendered output is hard, but we *know* that top left should be white.
    // So take a samples in the middle of each rectangle we drew and compare.
    // Note that we only use fully saturated colors to avoid any issues with color spaces.
    let rgba_buf = screenshot.to_rgba8(c).unwrap();
    let half_rect = cgmath::Vector2::new(width / 4.0, height / 4.0);
    let width = width as usize;
    assert_eq!(
        topleft.color.to_rgba(),
        get_rgba_sample(&rgba_buf, width, Point2::from(topleft.dest) + half_rect)
    );
    assert_eq!(
        topright.color.to_rgba(),
        get_rgba_sample(&rgba_buf, width, Point2::from(topright.dest) + half_rect)
    );
    assert_eq!(
        bottomleft.color.to_rgba(),
        get_rgba_sample(&rgba_buf, width, Point2::from(bottomleft.dest) + half_rect)
    );
    assert_eq!(
        bottomright.color.to_rgba(),
        get_rgba_sample(&rgba_buf, width, Point2::from(bottomright.dest) + half_rect)
    );

    // save screenshot (no check, just to see if it doesn't crash)
    screenshot
        .encode(c, graphics::ImageFormat::Png, "/screenshot_test.png")
        .unwrap();
}

#[test]
fn load_images() {
    let (c, _e) = &mut tests::make_context();
    let image = graphics::Image::new(c, "/player.png").unwrap();
    image
        .encode(c, graphics::ImageFormat::Png, "/player_save_test.png")
        .unwrap();
    let _i2 = graphics::Image::new(c, "/player_save_test.png").unwrap();
}

#[test]
fn sanity_check_window_sizes() {
    let (c, e) = &mut tests::make_context();

    // Make sure that window sizes are what we ask for, and not what hidpi gives us.
    let w = c.conf.window_mode.width;
    let h = c.conf.window_mode.height;
    let size = graphics::drawable_size(c);
    assert_eq!(w, size.0);
    assert_eq!(h, size.1);

    let outer_size = graphics::size(c);
    assert!(size.0 <= outer_size.0);
    assert!(size.1 <= outer_size.1);

    // Make sure resizing the window works.
    let w = 100.0;
    let h = 200.0;
    graphics::set_drawable_size(c, w, h).unwrap();
    // ahahaha this apparently REQUIRES a delay between setting
    // the size and it actually altering, at least on Linux X11
    std::thread::sleep(std::time::Duration::from_millis(100));
    // Maybe we need to run the event pump too?  It seems VERY flaky.
    // Sometimes you need one, sometimes you need both...
    e.poll_events(|event| {
        c.process_event(&event);
    });

    let size = graphics::drawable_size(c);
    assert_eq!(w, size.0);
    assert_eq!(h, size.1);
}

/// Ensure that the transform stack applies operations in the correct order.
#[test]
fn test_transform_stack_order() {
    let (ctx, _e) = &mut tests::make_context();
    let p1 = graphics::DrawParam::default();
    let p2 = graphics::DrawParam::default();
    let t1 = p1.to_matrix();
    let t2 = p2.to_matrix();
    graphics::push_transform(ctx, Some(t1));
    graphics::mul_transform(ctx, t2);
    let res = crate::nalgebra::Matrix4::<f32>::from(graphics::transform(ctx));
    let m1: crate::nalgebra::Matrix4<f32> = t1.into();
    let m2: crate::nalgebra::Matrix4<f32> = t2.into();
    assert_eq!(res, m2 * m1);
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

/// Logs a RRG-specific message at the error level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::error;
/// error!("some awkward error occured (code: {})", 42);
/// ```
#[macro_export]
macro_rules! error {
    ($($arg:tt)*) => {
        ::log::error!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the warn level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::warn;
/// warn!("received a strange number: {}", 1337);
/// ```
#[macro_export]
macro_rules! warn {
    ($($arg:tt)*) => {
        ::log::warn!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the info level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::info;
/// info!("running as '{}'", std::env::var("USER").unwrap());
/// ```
#[macro_export]
macro_rules! info {
    ($($arg:tt)*) => {
        ::log::info!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the debug level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::debug;
/// debug!("a bunch of very important numbers: {:?}", &[4, 8, 15, 16, 23, 42]);
/// ```
#[macro_export]
macro_rules! debug {
    ($($arg:tt)*) => {
        ::log::debug!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the trace level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::trace;
/// trace!("we are at ({}; {})", std::f32::consts::PI, std::f32::consts::E);
/// ```
#[macro_export]
macro_rules! trace {
    ($($arg:tt)*) => {
        ::log::trace!(target: "rrg", $($arg)*);
    }
}

/// Acknowledges a possible error and transforms the value into optional.
///
/// The `ack` macro will evaluate given expression that returns a result and,
/// in case of an error, log it at the specified level. Then, the errors is
/// simply discarded at the value is transformed into an `Option`.
///
/// This macro can be useful in cases where errors are not critical and are to
/// some extent expected. Just throwing them away without logging is not always
/// a good option, since they may include some useful information.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::ack;
/// use std::path::PathBuf;
///
/// let profile = ack! {
///     std::env::var("HOME"),
///     error: "home folder not specified"
/// }.and_then(|home| ack! {
///     std::fs::read([&home, ".profile"].iter().collect::<PathBuf>()),
///     error: "failed to read the profile file"
/// });
///
/// if let Some(profile) = profile {
///     println!("size of the profile file: {}", profile.len());
/// }
/// ```
#[macro_export]
macro_rules! ack {
    { $expr:expr, $level:ident: $message:literal } => {
        match $expr {
            Ok(value) => Some(value),
            Err(err) => {
                ::rrg_macro::$level!(concat!($message, ": {}"), err);
                None
            },
        }
    };
}
<commit_msg>Make the `ack` macro more general.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

/// Logs a RRG-specific message at the error level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::error;
/// error!("some awkward error occured (code: {})", 42);
/// ```
#[macro_export]
macro_rules! error {
    ($($arg:tt)*) => {
        ::log::error!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the warn level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::warn;
/// warn!("received a strange number: {}", 1337);
/// ```
#[macro_export]
macro_rules! warn {
    ($($arg:tt)*) => {
        ::log::warn!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the info level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::info;
/// info!("running as '{}'", std::env::var("USER").unwrap());
/// ```
#[macro_export]
macro_rules! info {
    ($($arg:tt)*) => {
        ::log::info!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the debug level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::debug;
/// debug!("a bunch of very important numbers: {:?}", &[4, 8, 15, 16, 23, 42]);
/// ```
#[macro_export]
macro_rules! debug {
    ($($arg:tt)*) => {
        ::log::debug!(target: "rrg", $($arg)*);
    }
}

/// Logs a RRG-specific message at the trace level.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::trace;
/// trace!("we are at ({}; {})", std::f32::consts::PI, std::f32::consts::E);
/// ```
#[macro_export]
macro_rules! trace {
    ($($arg:tt)*) => {
        ::log::trace!(target: "rrg", $($arg)*);
    }
}

/// Acknowledges a possible error and transforms the value into optional.
///
/// The `ack` macro will evaluate given expression that returns a result and,
/// in case of an error, log it at the specified level. Then, the errors is
/// simply discarded at the value is transformed into an `Option`.
///
/// This macro can be useful in cases where errors are not critical and are to
/// some extent expected. Just throwing them away without logging is not always
/// a good option, since they may include some useful information.
///
/// # Examples
///
/// ```no_run
/// # use rrg_macro::ack;
/// use std::path::PathBuf;
///
/// let profile = ack! {
///     std::env::var("HOME"),
///     error: "home folder not specified"
/// }.and_then(|home| ack! {
///     std::fs::read([&home, ".profile"].iter().collect::<PathBuf>()),
///     error: "failed to read the profile file"
/// });
///
/// if let Some(profile) = profile {
///     println!("size of the profile file: {}", profile.len());
/// }
/// ```
///
/// ```no_run
/// # use rrg_macro::ack;
/// let path = std::env::args().next().unwrap();
///
/// let mut content = String::new();
/// ack! {
///     std::fs::read_to_string(&mut content),
///     error: "failed to read '{}'", path
/// };
///
/// println!("{}", content);
/// ```
#[macro_export]
macro_rules! ack {
    // TODO: Find a way to remove this nasty code duplication.
    // TODO: Allow trailing comma for arguments.
    { $expr:expr, $level:ident: $message:literal } => {
        match $expr {
            Ok(value) => Some(value),
            Err(err) => {
                ::rrg_macro::$level! {
                    concat!($message, ": {}"), err
                };
                None
            },
        }
    };
    { $expr:expr, $level:ident: $message:literal, $($arg:expr),* } => {
        match $expr {
            Ok(value) => Some(value),
            Err(err) => {
                ::rrg_macro::$level! {
                    concat!($message, ": {}"), $($arg),*, err
                };
                None
            },
        }
    };
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

#![feature(rustc_attrs)]

#[rustc_mir]
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
    // Test passing a number of arguments including a fat pointer.
    // Also returning via an out pointer
    fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
        (a, b, c)
    }
    callee(a, b, c)
}

#[rustc_mir]
fn test2(a: isize) -> isize {
    // Test passing a single argument.
    // Not using out pointer.
    fn callee(a: isize) -> isize {
        a
    }
    callee(a)
}

struct Foo;
impl Foo {
    fn inherent_method(&self, a: isize) -> isize { a }
}

#[rustc_mir]
fn test3(x: &Foo, a: isize) -> isize {
    // Test calling inherent method
    x.inherent_method(a)
}

trait Bar {
    fn extension_method(&self, a: isize) -> isize { a }
}
impl Bar for Foo {}

#[rustc_mir]
fn test4(x: &Foo, a: isize) -> isize {
    // Test calling extension method
    x.extension_method(a)
}

#[rustc_mir]
fn test5(x: &Bar, a: isize) -> isize {
    // Test calling method on trait object
    x.extension_method(a)
}

// FIXME #30661: Although this function has the #[rustc_mir] attribute it never
//               was translated via the MIR implementation because attributes
//               where not passed along to trans::base::trans_fn() for generic
//               functions.
//               Uncomment this test once the thing it tests is fixed.
// #[rustc_mir]
// fn test6<T: Bar>(x: &T, a: isize) -> isize {
//     // Test calling extension method on generic callee
//     x.extension_method(a)
// }

trait One<T = Self> {
    fn one() -> T;
}
impl One for isize {
    fn one() -> isize { 1 }
}

#[rustc_mir]
fn test7() -> isize {
    // Test calling trait static method
    <isize as One>::one()
}

struct Two;
impl Two {
    fn two() -> isize { 2 }
}

#[rustc_mir]
fn test8() -> isize {
    // Test calling impl static method
    Two::two()
}

#[rustc_mir]
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
    where F: Fn(i32, i32) -> i32
{
    f(x, y)
}

#[rustc_mir]
fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    f(x, y)
}

#[rustc_mir]
fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    // This call goes through the Fn implementation for &Fn provided in
    // core::ops::impls. It expands to a static Fn::call() that calls the
    // Fn::call() implemenation of the object shim underneath.
    f(x, y)
}

fn main() {
    assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
    assert_eq!(test2(98), 98);
    assert_eq!(test3(&Foo, 42), 42);
    assert_eq!(test4(&Foo, 970), 970);
    assert_eq!(test5(&Foo, 8576), 8576);
    // see definition of test6() above
    // assert_eq!(test6(&Foo, 12367), 12367);
    assert_eq!(test7(), 1);
    assert_eq!(test8(), 2);

    let closure = |x: i32, y: i32| { x + y };
    assert_eq!(test_closure(&closure, 100, 1), 101);
    let function_object = &closure as &Fn(i32, i32) -> i32;
    assert_eq!(test_fn_object(function_object, 100, 2), 102);
    assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
}
<commit_msg>Reenable MIR test<commit_after>// Copyright 2015 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.

#![feature(rustc_attrs)]

#[rustc_mir]
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
    // Test passing a number of arguments including a fat pointer.
    // Also returning via an out pointer
    fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
        (a, b, c)
    }
    callee(a, b, c)
}

#[rustc_mir]
fn test2(a: isize) -> isize {
    // Test passing a single argument.
    // Not using out pointer.
    fn callee(a: isize) -> isize {
        a
    }
    callee(a)
}

struct Foo;
impl Foo {
    fn inherent_method(&self, a: isize) -> isize { a }
}

#[rustc_mir]
fn test3(x: &Foo, a: isize) -> isize {
    // Test calling inherent method
    x.inherent_method(a)
}

trait Bar {
    fn extension_method(&self, a: isize) -> isize { a }
}
impl Bar for Foo {}

#[rustc_mir]
fn test4(x: &Foo, a: isize) -> isize {
    // Test calling extension method
    x.extension_method(a)
}

#[rustc_mir]
fn test5(x: &Bar, a: isize) -> isize {
    // Test calling method on trait object
    x.extension_method(a)
}

#[rustc_mir]
fn test6<T: Bar>(x: &T, a: isize) -> isize {
    // Test calling extension method on generic callee
    x.extension_method(a)
}

trait One<T = Self> {
    fn one() -> T;
}
impl One for isize {
    fn one() -> isize { 1 }
}

#[rustc_mir]
fn test7() -> isize {
    // Test calling trait static method
    <isize as One>::one()
}

struct Two;
impl Two {
    fn two() -> isize { 2 }
}

#[rustc_mir]
fn test8() -> isize {
    // Test calling impl static method
    Two::two()
}

#[rustc_mir]
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
    where F: Fn(i32, i32) -> i32
{
    f(x, y)
}

#[rustc_mir]
fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    f(x, y)
}

#[rustc_mir]
fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    // This call goes through the Fn implementation for &Fn provided in
    // core::ops::impls. It expands to a static Fn::call() that calls the
    // Fn::call() implemenation of the object shim underneath.
    f(x, y)
}

fn main() {
    assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
    assert_eq!(test2(98), 98);
    assert_eq!(test3(&Foo, 42), 42);
    assert_eq!(test4(&Foo, 970), 970);
    assert_eq!(test5(&Foo, 8576), 8576);
    assert_eq!(test6(&Foo, 12367), 12367);
    assert_eq!(test7(), 1);
    assert_eq!(test8(), 2);

    let closure = |x: i32, y: i32| { x + y };
    assert_eq!(test_closure(&closure, 100, 1), 101);
    let function_object = &closure as &Fn(i32, i32) -> i32;
    assert_eq!(test_fn_object(function_object, 100, 2), 102);
    assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
}
<|endoftext|>