<commit_before>use RawFd;
use error::*;
use handler::*;
use nix::sys::socket::*;
use poll::*;
use slab::Slab;

#[derive(Debug, Clone, PartialEq)]
pub enum MuxCmd {
  Close,
  Keep,
}

#[derive(Debug)]
pub struct SyncMux<'p, H, P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'p>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>, // TODO + HandlerProp::get_interests()
{
  epfd: EpollFd,
  handlers: Slab<H, usize>,
  factory: P,
  _data: ::std::marker::PhantomData<&'p bool>,
  interests: EpollEventKind,
}

impl<'p, H, P> SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'static,
{
  pub fn new(max_handlers: usize, interests: EpollEventKind, epfd: EpollFd, factory: P)
             -> SyncMux<'p, H, P> {
    SyncMux {
      epfd: epfd,
      handlers: Slab::with_capacity(max_handlers),
      factory: factory,
      _data: ::std::marker::PhantomData {},
      interests: interests,
    }
  }
}

impl<'p, H, P> Clone for SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + Clone + 'static,
{
  fn clone(&self) -> Self {
    SyncMux {
      epfd: self.epfd,
      handlers: Slab::with_capacity(self.handlers.capacity()),
      factory: self.factory.clone(),
      interests: self.interests.clone(),
      _data: ::std::marker::PhantomData {},
    }
  }
}

impl<'p, H, P> Reset for SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'static,
{
  fn reset(&mut self, epfd: EpollFd) {
    self.epfd = epfd;
  }
}

#[macro_export]
macro_rules! keep_or {
  ($cmd:expr, $b: block) => {{
    match $cmd {
      MuxCmd::Close => $b,
      _ => (),
    }
  }}
}

#[macro_export]
macro_rules! keep {
  ($cmd:expr) => {{
    keep_or_return!($cmd, MuxCmd::Close)
  }}
}

#[macro_export]
macro_rules! keep_or_return {
  ($cmd:expr, $ret: expr) => {{
    keep_or!($cmd, { return $ret; });
  }}
}

macro_rules! keep_or_close {
  ($cmd:expr, $clifd: expr) => {{
    keep_or!($cmd, { close!($clifd); });
  }}
}

macro_rules! close {
  ($clifd: expr) => {{
    perror!("unistd::close", ::close($clifd));
    return EpollCmd::Poll;
  }}
}

macro_rules! ok_or_close {
  ($cmd:expr, $clifd: expr) => {{
    match $cmd {
      Err(e) => {
        error!("{}", e);
        close!($clifd);
      },
      Ok(res) => res,
    }
  }}
}

macro_rules! some_or_close {
  ($cmd:expr, $clifd: expr, $msg: expr) => {{
    match $cmd {
      None => {
        error!("{}", $msg);
        close!($clifd);
      },
      Some(res) => res,
    }
  }}
}

impl<'p, H, P> Handler<'p, EpollEvent, EpollCmd> for SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'static,
{
  fn on_next(&'p mut self, mut event: EpollEvent) -> EpollCmd {

    match Action::decode(event.data) {

      Action::Notify(i, clifd) => {
        let mut entry = some_or_close!(self.handlers.entry(i), clifd, "no handler at index={}");

        event.data = clifd as u64;

        keep_or!(entry.get_mut().on_next(event), {
          self.factory.done(entry.remove(), i);
          close!(clifd);
        });
      }

      Action::New(data) => {
        let srvfd = data as i32;
        match eintr!(accept, "accept", srvfd) {
          Ok(Some(clifd)) => {
            debug!("accept: accepted new tcp client {}", &clifd);
            // TODO grow slab
            let entry = some_or_close!(self.handlers.vacant_entry(),
                                       clifd,
                                       "reached maximum number of handlers");
            let i = entry.index();

            let mut h = self.factory.new(self.epfd, i, clifd);

            let mut event = EpollEvent {
              events: self.interests,
              data: clifd as u64,
            };
            keep_or_close!(h.on_next(event), clifd);

            event.data = Action::encode(Action::Notify(i, clifd));
            ok_or_close!(self.epfd.register(clifd, &event), clifd);

            entry.insert(h);
          }
          Ok(None) => debug!("accept4: socket not ready"),
          Err(e) => report_err!("accept4: {}", e.into()),
        }
      }
    };

    EpollCmd::Poll
  }
}

pub enum Action {
  Notify(usize, RawFd),
  New(u64),
}

impl Action {
  #[inline(always)]
  pub fn encode(action: Action) -> u64 {
    match action {
      Action::Notify(data, fd) => ((fd as u64) << 31) | ((data as u64) << 15) | 0,
      Action::New(data) => data,
    }
  }

  #[inline(always)]
  pub fn decode(data: u64) -> Action {
    let arg1 = ((data >> 15) & 0xffff) as usize;
    let fd = (data >> 31) as i32;
    match data & 0x7fff {
      0 => Action::Notify(arg1, fd),
      _ => Action::New(data),
    }
  }
}

#[cfg(test)]
mod tests {
  use super::Action;
  #[test]
  fn decode_encode_new_action() {
    let data = Action::encode(Action::New(::std::u64::MAX));

    if let Action::New(fd) = Action::decode(data) {
      assert!(fd == ::std::u64::MAX);
    } else {
      panic!("action is not Action::New")
    }
  }

  #[test]
  fn decode_encode_notify_action() {
    let data = Action::encode(Action::Notify(10110, 0));

    if let Action::Notify(data, fd) = Action::decode(data) {
      assert!(data == 10110);
      assert!(fd == 0);
    } else {
      panic!("action is not Action::Notify")
    }
  }
}
<commit_msg>fix mux error message<commit_after>use RawFd;
use error::*;
use handler::*;
use nix::sys::socket::*;
use poll::*;
use slab::Slab;

#[derive(Debug, Clone, PartialEq)]
pub enum MuxCmd {
  Close,
  Keep,
}

#[derive(Debug)]
pub struct SyncMux<'p, H, P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'p>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>, // TODO + HandlerProp::get_interests()
{
  epfd: EpollFd,
  handlers: Slab<H, usize>,
  factory: P,
  _data: ::std::marker::PhantomData<&'p bool>,
  interests: EpollEventKind,
}

impl<'p, H, P> SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'static,
{
  pub fn new(max_handlers: usize, interests: EpollEventKind, epfd: EpollFd, factory: P)
             -> SyncMux<'p, H, P> {
    SyncMux {
      epfd: epfd,
      handlers: Slab::with_capacity(max_handlers),
      factory: factory,
      _data: ::std::marker::PhantomData {},
      interests: interests,
    }
  }
}

impl<'p, H, P> Clone for SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + Clone + 'static,
{
  fn clone(&self) -> Self {
    SyncMux {
      epfd: self.epfd,
      handlers: Slab::with_capacity(self.handlers.capacity()),
      factory: self.factory.clone(),
      interests: self.interests.clone(),
      _data: ::std::marker::PhantomData {},
    }
  }
}

impl<'p, H, P> Reset for SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'static,
{
  fn reset(&mut self, epfd: EpollFd) {
    self.epfd = epfd;
  }
}

#[macro_export]
macro_rules! keep_or {
  ($cmd:expr, $b: block) => {{
    match $cmd {
      MuxCmd::Close => $b,
      _ => (),
    }
  }}
}

#[macro_export]
macro_rules! keep {
  ($cmd:expr) => {{
    keep_or_return!($cmd, MuxCmd::Close)
  }}
}

#[macro_export]
macro_rules! keep_or_return {
  ($cmd:expr, $ret: expr) => {{
    keep_or!($cmd, { return $ret; });
  }}
}

macro_rules! keep_or_close {
  ($cmd:expr, $clifd: expr) => {{
    keep_or!($cmd, { close!($clifd); });
  }}
}

macro_rules! close {
  ($clifd: expr) => {{
    perror!("unistd::close", ::close($clifd));
    return EpollCmd::Poll;
  }}
}

macro_rules! ok_or_close {
  ($cmd:expr, $clifd: expr) => {{
    match $cmd {
      Err(e) => {
        error!("{}", e);
        close!($clifd);
      },
      Ok(res) => res,
    }
  }}
}

macro_rules! some_or_close {
  ($cmd:expr, $clifd: expr) => {{
    match $cmd {
      None => {
        close!($clifd);
      },
      Some(res) => res,
    }
  }}
}

impl<'p, H, P> Handler<'p, EpollEvent, EpollCmd> for SyncMux<'p, H, P>
  where for<'h> H: Handler<'h, EpollEvent, MuxCmd>,
        P: HandlerFactory<'p, H, EpollEvent, MuxCmd> + 'static,
{
  fn on_next(&'p mut self, mut event: EpollEvent) -> EpollCmd {

    match Action::decode(event.data) {

      Action::Notify(i, clifd) => {
        let mut entry = some_or_close!(self.handlers.entry(i), clifd);

        event.data = clifd as u64;

        keep_or!(entry.get_mut().on_next(event), {
          self.factory.done(entry.remove(), i);
          close!(clifd);
        });
      }

      Action::New(data) => {
        let srvfd = data as i32;
        match eintr!(accept, "accept", srvfd) {
          Ok(Some(clifd)) => {
            debug!("accept: accepted new tcp client {}", &clifd);
            // TODO grow slab
            let entry = some_or_close!(self.handlers.vacant_entry(), clifd);
            let i = entry.index();

            let mut h = self.factory.new(self.epfd, i, clifd);

            let mut event = EpollEvent {
              events: self.interests,
              data: clifd as u64,
            };
            keep_or_close!(h.on_next(event), clifd);

            event.data = Action::encode(Action::Notify(i, clifd));
            ok_or_close!(self.epfd.register(clifd, &event), clifd);

            entry.insert(h);
          }
          Ok(None) => debug!("accept4: socket not ready"),
          Err(e) => report_err!("accept4: {}", e.into()),
        }
      }
    };

    EpollCmd::Poll
  }
}

pub enum Action {
  Notify(usize, RawFd),
  New(u64),
}

impl Action {
  #[inline(always)]
  pub fn encode(action: Action) -> u64 {
    match action {
      Action::Notify(data, fd) => ((fd as u64) << 31) | ((data as u64) << 15) | 0,
      Action::New(data) => data,
    }
  }

  #[inline(always)]
  pub fn decode(data: u64) -> Action {
    let arg1 = ((data >> 15) & 0xffff) as usize;
    let fd = (data >> 31) as i32;
    match data & 0x7fff {
      0 => Action::Notify(arg1, fd),
      _ => Action::New(data),
    }
  }
}

#[cfg(test)]
mod tests {
  use super::Action;
  #[test]
  fn decode_encode_new_action() {
    let data = Action::encode(Action::New(::std::u64::MAX));

    if let Action::New(fd) = Action::decode(data) {
      assert!(fd == ::std::u64::MAX);
    } else {
      panic!("action is not Action::New")
    }
  }

  #[test]
  fn decode_encode_notify_action() {
    let data = Action::encode(Action::Notify(10110, 0));

    if let Action::Notify(data, fd) = Action::decode(data) {
      assert!(data == 10110);
      assert!(fd == 0);
    } else {
      panic!("action is not Action::Notify")
    }
  }
}
<|endoftext|>


<commit_before>//! A collection of traits abstracting over Listeners and Streams.
use std::any::{Any, TypeId};
use std::fmt;
use std::io::{self, Read, Write};
use std::net::{SocketAddr, ToSocketAddrs, TcpStream, TcpListener};
use std::mem;
use std::path::Path;
use std::sync::Arc;

use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE};
use openssl::ssl::SslMethod::Sslv23;
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};
use openssl::x509::X509FileType;

use typeable::Typeable;
use {traitobject};

/// The write-status indicating headers have not been written.
pub enum Fresh {}

/// The write-status indicating headers have been written.
pub enum Streaming {}

/// An abstraction to listen for connections on a certain port.
pub trait NetworkListener: Clone {
    /// The stream produced for each connection.
    type Stream: NetworkStream + Send + Clone;
    /// Listens on a socket.
    //fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>;

    /// Returns an iterator of streams.
    fn accept(&mut self) -> io::Result<Self::Stream>;

    /// Get the address this Listener ended up listening on.
    fn local_addr(&mut self) -> io::Result<SocketAddr>;

    /// Closes the Acceptor, so no more incoming connections will be handled.
//    fn close(&mut self) -> io::Result<()>;

    /// Returns an iterator over incoming connections.
    fn incoming(&mut self) -> NetworkConnections<Self> {
        NetworkConnections(self)
    }
}

/// An iterator wrapper over a NetworkAcceptor.
pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N);

impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> {
    type Item = io::Result<N::Stream>;
    fn next(&mut self) -> Option<io::Result<N::Stream>> {
        Some(self.0.accept())
    }
}

/// An abstraction over streams that a Server can utilize.
pub trait NetworkStream: Read + Write + Any + StreamClone + Send + Typeable {
    /// Get the remote address of the underlying connection.
    fn peer_addr(&mut self) -> io::Result<SocketAddr>;
}

#[doc(hidden)]
pub trait StreamClone {
    fn clone_box(&self) -> Box<NetworkStream + Send>;
}

impl<T: NetworkStream + Send + Clone> StreamClone for T {
    #[inline]
    fn clone_box(&self) -> Box<NetworkStream + Send> {
        Box::new(self.clone())
    }
}

/// A connector creates a NetworkStream.
pub trait NetworkConnector {
    /// Type of Stream to create
    type Stream: Into<Box<NetworkStream + Send>>;
    /// Connect to a remote address.
    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>;
}

impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> {
    fn from(s: T) -> Box<NetworkStream + Send> {
        Box::new(s)
    }
}

impl fmt::Debug for Box<NetworkStream + Send> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad("Box<NetworkStream>")
    }
}

impl Clone for Box<NetworkStream + Send> {
    #[inline]
    fn clone(&self) -> Box<NetworkStream + Send> { self.clone_box() }
}

impl NetworkStream + Send {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(traitobject::data(self))
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(traitobject::data_mut(self))
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream + Send>) -> Box<T>  {
        let raw: *mut NetworkStream = mem::transmute(self);
        mem::transmute(traitobject::data_mut(raw))
    }
}

impl NetworkStream + Send {
    /// Is the underlying type in this trait object a T?
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        (*self).get_type() == TypeId::of::<T>()
    }

    /// If the underlying type is T, get a reference to the contained data.
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_ref_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, get a mutable reference to the contained
    /// data.
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_mut_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, extract it.
    pub fn downcast<T: Any>(self: Box<NetworkStream + Send>)
            -> Result<Box<T>, Box<NetworkStream + Send>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}

/// A `NetworkListener` for `HttpStream`s.
pub enum HttpListener {
    /// Http variant.
    Http(TcpListener),
    /// Https variant. The two paths point to the certificate and key PEM files, in that order.
    Https(TcpListener, Arc<SslContext>)
}

impl Clone for HttpListener {
    fn clone(&self) -> HttpListener {
        match *self {
            HttpListener::Http(ref tcp) => HttpListener::Http(tcp.try_clone().unwrap()),
            HttpListener::Https(ref tcp, ref ssl) => HttpListener::Https(tcp.try_clone().unwrap(), ssl.clone()),
        }
    }
}

impl HttpListener {

    /// Start listening to an address over HTTP.
    pub fn http<To: ToSocketAddrs>(addr: To) -> io::Result<HttpListener> {
        Ok(HttpListener::Http(try!(TcpListener::bind(addr))))
    }

    /// Start listening to an address over HTTPS.
    pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> io::Result<HttpListener> {
        let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
        try!(ssl_context.set_cipher_list("DEFAULT").map_err(lift_ssl_error));
        try!(ssl_context.set_certificate_file(cert, X509FileType::PEM).map_err(lift_ssl_error));
        try!(ssl_context.set_private_key_file(key, X509FileType::PEM).map_err(lift_ssl_error));
        ssl_context.set_verify(SSL_VERIFY_NONE, None);
        Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context)))
    }
}

impl NetworkListener for HttpListener {
    type Stream = HttpStream;

    #[inline]
    fn accept(&mut self) -> io::Result<HttpStream> {
        Ok(match *self {
            HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)),
            HttpListener::Https(ref mut tcp, ref ssl_context) => {
                let stream = CloneTcpStream(try!(tcp.accept()).0);
                match SslStream::new_server(&**ssl_context, stream) {
                    Ok(ssl_stream) => HttpStream::Https(ssl_stream),
                    Err(StreamError(e)) => {
                        return Err(io::Error::new(io::ErrorKind::ConnectionAborted,
                                                  e));
                    },
                    Err(e) => return Err(lift_ssl_error(e))
                }
            }
        })
    }

    #[inline]
    fn local_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpListener::Http(ref mut tcp) => tcp.local_addr(),
            HttpListener::Https(ref mut tcp, _) => tcp.local_addr(),
        }
    }
}

#[doc(hidden)]
pub struct CloneTcpStream(TcpStream);

impl Clone for CloneTcpStream{
    #[inline]
    fn clone(&self) -> CloneTcpStream {
        CloneTcpStream(self.0.try_clone().unwrap())
    }
}

impl Read for CloneTcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for CloneTcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// A wrapper around a TcpStream.
#[derive(Clone)]
pub enum HttpStream {
    /// A stream over the HTTP protocol.
    Http(CloneTcpStream),
    /// A stream over the HTTP protocol, protected by SSL.
    Https(SslStream<CloneTcpStream>),
}

impl fmt::Debug for HttpStream {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      HttpStream::Http(_) => write!(fmt, "Http HttpStream"),
      HttpStream::Https(_) => write!(fmt, "Https HttpStream"),
    }
  }
}

impl Read for HttpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.read(buf),
            HttpStream::Https(ref mut inner) => inner.read(buf)
        }
    }
}

impl Write for HttpStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.write(msg),
            HttpStream::Https(ref mut inner) => inner.write(msg)
        }
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.flush(),
            HttpStream::Https(ref mut inner) => inner.flush(),
        }
    }
}

impl NetworkStream for HttpStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.0.peer_addr(),
            HttpStream::Https(ref mut inner) => inner.get_mut().0.peer_addr()
        }
    }
}

/// A connector that will produce HttpStreams.
pub struct HttpConnector(pub Option<ContextVerifier>);

/// A method that can set verification methods on an SSL context
pub type ContextVerifier = Box<FnMut(&mut SslContext) -> () + Send>;

impl NetworkConnector for HttpConnector {
    type Stream = HttpStream;

    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> {
        let addr = &(host, port);
        match scheme {
            "http" => {
                debug!("http scheme");
                Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr)))))
            },
            "https" => {
                debug!("https scheme");
                let stream = CloneTcpStream(try!(TcpStream::connect(addr)));
                let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
                if let Some(ref mut verifier) = self.0 {
                    verifier(&mut context);
                }
                let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
                try!(ssl.set_hostname(host).map_err(lift_ssl_error));
                let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
                Ok(HttpStream::Https(stream))
            },
            _ => {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                "Invalid scheme for Http"))
            }
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> io::Error {
    debug!("lift_ssl_error: {:?}", ssl);
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => io::Error::new(io::ErrorKind::ConnectionAborted,
                                         "SSL Connection Closed"),
        e@OpenSslErrors(..) => io::Error::new(io::ErrorKind::Other, e)
    }
}

#[cfg(test)]
mod tests {
    use mock::MockStream;
    use super::NetworkStream;

    #[test]
    fn test_downcast_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = stream.downcast::<MockStream>().ok().unwrap();
        assert_eq!(mock, Box::new(MockStream::new()));

    }

    #[test]
    fn test_downcast_unchecked_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = unsafe { stream.downcast_unchecked::<MockStream>() };
        assert_eq!(mock, Box::new(MockStream::new()));

    }

}
<commit_msg>feat(client): remove Clone requirement for NetworkStream in Client<commit_after>//! A collection of traits abstracting over Listeners and Streams.
use std::any::{Any, TypeId};
use std::fmt;
use std::io::{self, Read, Write};
use std::net::{SocketAddr, ToSocketAddrs, TcpStream, TcpListener};
use std::mem;
use std::path::Path;
use std::sync::Arc;

use openssl::ssl::{Ssl, SslStream, SslContext, SSL_VERIFY_NONE};
use openssl::ssl::SslMethod::Sslv23;
use openssl::ssl::error::{SslError, StreamError, OpenSslErrors, SslSessionClosed};
use openssl::x509::X509FileType;

use typeable::Typeable;
use {traitobject};

/// The write-status indicating headers have not been written.
pub enum Fresh {}

/// The write-status indicating headers have been written.
pub enum Streaming {}

/// An abstraction to listen for connections on a certain port.
pub trait NetworkListener: Clone {
    /// The stream produced for each connection.
    type Stream: NetworkStream + Send + Clone;
    /// Listens on a socket.
    //fn listen<To: ToSocketAddrs>(&mut self, addr: To) -> io::Result<Self::Acceptor>;

    /// Returns an iterator of streams.
    fn accept(&mut self) -> io::Result<Self::Stream>;

    /// Get the address this Listener ended up listening on.
    fn local_addr(&mut self) -> io::Result<SocketAddr>;

    /// Closes the Acceptor, so no more incoming connections will be handled.
//    fn close(&mut self) -> io::Result<()>;

    /// Returns an iterator over incoming connections.
    fn incoming(&mut self) -> NetworkConnections<Self> {
        NetworkConnections(self)
    }
}

/// An iterator wrapper over a NetworkAcceptor.
pub struct NetworkConnections<'a, N: NetworkListener + 'a>(&'a mut N);

impl<'a, N: NetworkListener + 'a> Iterator for NetworkConnections<'a, N> {
    type Item = io::Result<N::Stream>;
    fn next(&mut self) -> Option<io::Result<N::Stream>> {
        Some(self.0.accept())
    }
}

/// An abstraction over streams that a Server can utilize.
pub trait NetworkStream: Read + Write + Any + Send + Typeable {
    /// Get the remote address of the underlying connection.
    fn peer_addr(&mut self) -> io::Result<SocketAddr>;
}

/// A connector creates a NetworkStream.
pub trait NetworkConnector {
    /// Type of Stream to create
    type Stream: Into<Box<NetworkStream + Send>>;
    /// Connect to a remote address.
    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<Self::Stream>;
}

impl<T: NetworkStream + Send> From<T> for Box<NetworkStream + Send> {
    fn from(s: T) -> Box<NetworkStream + Send> {
        Box::new(s)
    }
}

impl fmt::Debug for Box<NetworkStream + Send> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.pad("Box<NetworkStream>")
    }
}

impl NetworkStream + Send {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(traitobject::data(self))
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(traitobject::data_mut(self))
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<NetworkStream + Send>) -> Box<T>  {
        let raw: *mut NetworkStream = mem::transmute(self);
        mem::transmute(traitobject::data_mut(raw))
    }
}

impl NetworkStream + Send {
    /// Is the underlying type in this trait object a T?
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        (*self).get_type() == TypeId::of::<T>()
    }

    /// If the underlying type is T, get a reference to the contained data.
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_ref_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, get a mutable reference to the contained
    /// data.
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_mut_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, extract it.
    pub fn downcast<T: Any>(self: Box<NetworkStream + Send>)
            -> Result<Box<T>, Box<NetworkStream + Send>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}

/// A `NetworkListener` for `HttpStream`s.
pub enum HttpListener {
    /// Http variant.
    Http(TcpListener),
    /// Https variant. The two paths point to the certificate and key PEM files, in that order.
    Https(TcpListener, Arc<SslContext>)
}

impl Clone for HttpListener {
    fn clone(&self) -> HttpListener {
        match *self {
            HttpListener::Http(ref tcp) => HttpListener::Http(tcp.try_clone().unwrap()),
            HttpListener::Https(ref tcp, ref ssl) => HttpListener::Https(tcp.try_clone().unwrap(), ssl.clone()),
        }
    }
}

impl HttpListener {

    /// Start listening to an address over HTTP.
    pub fn http<To: ToSocketAddrs>(addr: To) -> io::Result<HttpListener> {
        Ok(HttpListener::Http(try!(TcpListener::bind(addr))))
    }

    /// Start listening to an address over HTTPS.
    pub fn https<To: ToSocketAddrs>(addr: To, cert: &Path, key: &Path) -> io::Result<HttpListener> {
        let mut ssl_context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
        try!(ssl_context.set_cipher_list("DEFAULT").map_err(lift_ssl_error));
        try!(ssl_context.set_certificate_file(cert, X509FileType::PEM).map_err(lift_ssl_error));
        try!(ssl_context.set_private_key_file(key, X509FileType::PEM).map_err(lift_ssl_error));
        ssl_context.set_verify(SSL_VERIFY_NONE, None);
        Ok(HttpListener::Https(try!(TcpListener::bind(addr)), Arc::new(ssl_context)))
    }
}

impl NetworkListener for HttpListener {
    type Stream = HttpStream;

    #[inline]
    fn accept(&mut self) -> io::Result<HttpStream> {
        Ok(match *self {
            HttpListener::Http(ref mut tcp) => HttpStream::Http(CloneTcpStream(try!(tcp.accept()).0)),
            HttpListener::Https(ref mut tcp, ref ssl_context) => {
                let stream = CloneTcpStream(try!(tcp.accept()).0);
                match SslStream::new_server(&**ssl_context, stream) {
                    Ok(ssl_stream) => HttpStream::Https(ssl_stream),
                    Err(StreamError(e)) => {
                        return Err(io::Error::new(io::ErrorKind::ConnectionAborted,
                                                  e));
                    },
                    Err(e) => return Err(lift_ssl_error(e))
                }
            }
        })
    }

    #[inline]
    fn local_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpListener::Http(ref mut tcp) => tcp.local_addr(),
            HttpListener::Https(ref mut tcp, _) => tcp.local_addr(),
        }
    }
}

#[doc(hidden)]
pub struct CloneTcpStream(TcpStream);

impl Clone for CloneTcpStream{
    #[inline]
    fn clone(&self) -> CloneTcpStream {
        CloneTcpStream(self.0.try_clone().unwrap())
    }
}

impl Read for CloneTcpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for CloneTcpStream {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// A wrapper around a TcpStream.
#[derive(Clone)]
pub enum HttpStream {
    /// A stream over the HTTP protocol.
    Http(CloneTcpStream),
    /// A stream over the HTTP protocol, protected by SSL.
    Https(SslStream<CloneTcpStream>),
}

impl fmt::Debug for HttpStream {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      HttpStream::Http(_) => write!(fmt, "Http HttpStream"),
      HttpStream::Https(_) => write!(fmt, "Https HttpStream"),
    }
  }
}

impl Read for HttpStream {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.read(buf),
            HttpStream::Https(ref mut inner) => inner.read(buf)
        }
    }
}

impl Write for HttpStream {
    #[inline]
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.write(msg),
            HttpStream::Https(ref mut inner) => inner.write(msg)
        }
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.flush(),
            HttpStream::Https(ref mut inner) => inner.flush(),
        }
    }
}

impl NetworkStream for HttpStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        match *self {
            HttpStream::Http(ref mut inner) => inner.0.peer_addr(),
            HttpStream::Https(ref mut inner) => inner.get_mut().0.peer_addr()
        }
    }
}

/// A connector that will produce HttpStreams.
pub struct HttpConnector(pub Option<ContextVerifier>);

/// A method that can set verification methods on an SSL context
pub type ContextVerifier = Box<FnMut(&mut SslContext) -> () + Send>;

impl NetworkConnector for HttpConnector {
    type Stream = HttpStream;

    fn connect(&mut self, host: &str, port: u16, scheme: &str) -> io::Result<HttpStream> {
        let addr = &(host, port);
        match scheme {
            "http" => {
                debug!("http scheme");
                Ok(HttpStream::Http(CloneTcpStream(try!(TcpStream::connect(addr)))))
            },
            "https" => {
                debug!("https scheme");
                let stream = CloneTcpStream(try!(TcpStream::connect(addr)));
                let mut context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
                if let Some(ref mut verifier) = self.0 {
                    verifier(&mut context);
                }
                let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
                try!(ssl.set_hostname(host).map_err(lift_ssl_error));
                let stream = try!(SslStream::new(&context, stream).map_err(lift_ssl_error));
                Ok(HttpStream::Https(stream))
            },
            _ => {
                Err(io::Error::new(io::ErrorKind::InvalidInput,
                                "Invalid scheme for Http"))
            }
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> io::Error {
    debug!("lift_ssl_error: {:?}", ssl);
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => io::Error::new(io::ErrorKind::ConnectionAborted,
                                         "SSL Connection Closed"),
        e@OpenSslErrors(..) => io::Error::new(io::ErrorKind::Other, e)
    }
}

#[cfg(test)]
mod tests {
    use mock::MockStream;
    use super::NetworkStream;

    #[test]
    fn test_downcast_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = stream.downcast::<MockStream>().ok().unwrap();
        assert_eq!(mock, Box::new(MockStream::new()));

    }

    #[test]
    fn test_downcast_unchecked_box_stream() {
        // FIXME: Use Type ascription
        let stream: Box<NetworkStream + Send> = Box::new(MockStream::new());

        let mock = unsafe { stream.downcast_unchecked::<MockStream>() };
        assert_eq!(mock, Box::new(MockStream::new()));

    }

}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::{Read, Write};

use httparse;
use hyper;
use hyper::method::Method;
use hyper::net::{HttpConnector, HttpsStream, NetworkConnector, SslClient};
use hyper::version::HttpVersion;

use proxy::ProxyInfo;

/// A connector that uses an HTTP proxy server (pass-through for plaintext and tunneled for SSL
/// sessions).
pub struct ProxyHttpsConnector<S: SslClient> {
    proxy: ProxyInfo,
    proxy_connector: HttpConnector,
    ssl_client: S,
}

impl<S: SslClient> ProxyHttpsConnector<S> {
    /// Creates a new connection using the provided proxy server configuration and SSL
    /// implementation.
    pub fn new(proxy: ProxyInfo, ssl: S) -> hyper::Result<Self> {
        Ok(ProxyHttpsConnector {
            proxy: proxy,
            proxy_connector: HttpConnector,
            ssl_client: ssl,
        })
    }
}

impl<S: SslClient> NetworkConnector for ProxyHttpsConnector<S> {
    type Stream = HttpsStream<S::Stream>;

    fn connect(&self, host: &str, port: u16, scheme: &str) -> hyper::Result<Self::Stream> {
        // Initial connection to the proxy server, using an `HttpConnector`
        let mut stream =
            self.proxy_connector
                .connect(self.proxy.host(), self.proxy.port(), "http")?;
        match scheme {
            "https" => {
                // If the target URL is an `"https"` scheme, then we use proxy/TCP tunneling as
                // per the RFC draft:
                // http://www.web-cache.com/Writings/Internet-Drafts/
                // draft-luotonen-web-proxy-tunneling-01.txt
                //
                // We can't yet use hyper directly and therefore use the underlying http parsing
                // library to establish the connection and parse the response. This implementation
                // is largely based on hyper's internal proxy tunneling code.
                let mut connect_msg = format!(
                    "{method} {host}:{port} {version}\r\nHost: \
                     {host}:{port}\r\n",
                    method = Method::Connect,
                    version = HttpVersion::Http11,
                    host = host,
                    port = port
                );
                if let Some(header_value) = self.proxy.authorization_header_value() {
                    connect_msg.push_str(&format!("Proxy-Authorization: {}\r\n", header_value));
                };
                connect_msg.push_str("\r\n");
                debug!(
                    "Proxy {}:{} {:?}",
                    self.proxy.host(),
                    self.proxy.port(),
                    connect_msg.trim().replace("\r\n", ", ")
                );
                stream.write_all(connect_msg.as_bytes())?;
                stream.flush()?;
                let mut buf = [0; 1024];
                let mut n = 0;
                while n < buf.len() {
                    n += stream.read(&mut buf[n..])?;
                    let mut headers = [httparse::EMPTY_HEADER; 10];
                    let mut res = httparse::Response::new(&mut headers);
                    if res.parse(&buf[..n])?.is_complete() {
                        let code = res.code.expect("complete parsing lost code");
                        if code >= 200 && code < 300 {
                            debug!(
                                "Proxy {}:{} CONNECT success = {}",
                                self.proxy.host(),
                                self.proxy.port(),
                                code
                            );
                            return self.ssl_client
                                .wrap_client(stream, host)
                                .map(HttpsStream::Https);
                        } else {
                            debug!(
                                "Proxy {}:{} CONNECT failed response = {}",
                                self.proxy.host(),
                                self.proxy.port(),
                                code
                            );
                            return Err(hyper::Error::Status);
                        }
                    }
                }
                Err(hyper::Error::TooLarge)
            }
            _ => Ok(HttpsStream::Http(stream)),
        }
    }
}
<commit_msg>[ci,rustfmt] Formatting due to rustfmt 0.8.2 in Rust 1.28.0.<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::{Read, Write};

use httparse;
use hyper;
use hyper::method::Method;
use hyper::net::{HttpConnector, HttpsStream, NetworkConnector, SslClient};
use hyper::version::HttpVersion;

use proxy::ProxyInfo;

/// A connector that uses an HTTP proxy server (pass-through for plaintext and tunneled for SSL
/// sessions).
pub struct ProxyHttpsConnector<S: SslClient> {
    proxy: ProxyInfo,
    proxy_connector: HttpConnector,
    ssl_client: S,
}

impl<S: SslClient> ProxyHttpsConnector<S> {
    /// Creates a new connection using the provided proxy server configuration and SSL
    /// implementation.
    pub fn new(proxy: ProxyInfo, ssl: S) -> hyper::Result<Self> {
        Ok(ProxyHttpsConnector {
            proxy: proxy,
            proxy_connector: HttpConnector,
            ssl_client: ssl,
        })
    }
}

impl<S: SslClient> NetworkConnector for ProxyHttpsConnector<S> {
    type Stream = HttpsStream<S::Stream>;

    fn connect(&self, host: &str, port: u16, scheme: &str) -> hyper::Result<Self::Stream> {
        // Initial connection to the proxy server, using an `HttpConnector`
        let mut stream =
            self.proxy_connector
                .connect(self.proxy.host(), self.proxy.port(), "http")?;
        match scheme {
            "https" => {
                // If the target URL is an `"https"` scheme, then we use proxy/TCP tunneling as
                // per the RFC draft:
                // http://www.web-cache.com/Writings/Internet-Drafts/
                // draft-luotonen-web-proxy-tunneling-01.txt
                //
                // We can't yet use hyper directly and therefore use the underlying http parsing
                // library to establish the connection and parse the response. This implementation
                // is largely based on hyper's internal proxy tunneling code.
                let mut connect_msg = format!(
                    "{method} {host}:{port} {version}\r\nHost: \
                     {host}:{port}\r\n",
                    method = Method::Connect,
                    version = HttpVersion::Http11,
                    host = host,
                    port = port
                );
                if let Some(header_value) = self.proxy.authorization_header_value() {
                    connect_msg.push_str(&format!("Proxy-Authorization: {}\r\n", header_value));
                };
                connect_msg.push_str("\r\n");
                debug!(
                    "Proxy {}:{} {:?}",
                    self.proxy.host(),
                    self.proxy.port(),
                    connect_msg.trim().replace("\r\n", ", ")
                );
                stream.write_all(connect_msg.as_bytes())?;
                stream.flush()?;
                let mut buf = [0; 1024];
                let mut n = 0;
                while n < buf.len() {
                    n += stream.read(&mut buf[n..])?;
                    let mut headers = [httparse::EMPTY_HEADER; 10];
                    let mut res = httparse::Response::new(&mut headers);
                    if res.parse(&buf[..n])?.is_complete() {
                        let code = res.code.expect("complete parsing lost code");
                        if code >= 200 && code < 300 {
                            debug!(
                                "Proxy {}:{} CONNECT success = {}",
                                self.proxy.host(),
                                self.proxy.port(),
                                code
                            );
                            return self
                                .ssl_client
                                .wrap_client(stream, host)
                                .map(HttpsStream::Https);
                        } else {
                            debug!(
                                "Proxy {}:{} CONNECT failed response = {}",
                                self.proxy.host(),
                                self.proxy.port(),
                                code
                            );
                            return Err(hyper::Error::Status);
                        }
                    }
                }
                Err(hyper::Error::TooLarge)
            }
            _ => Ok(HttpsStream::Http(stream)),
        }
    }
}
<|endoftext|>


<commit_before>//! Points on the 2D character grid.

use XY;
use num::traits::Zero;
use std::cmp::{Ordering, max, min};

use std::ops::{Add, Div, Mul, Sub};

/// Simple 2D size, in cells.
///
/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
/// currently shown on the [`XY`] page.
///
/// [#32077]: https://github.com/rust-lang/rust/issues/32077
/// [`XY`]: ../struct.XY.html
pub type Vec2 = XY<usize>;

impl PartialOrd for XY<usize> {
    /// `a < b` <=> `a.x < b.x && a.y < b.y`
    fn partial_cmp(&self, other: &Vec2) -> Option<Ordering> {
        if self == other {
            Some(Ordering::Equal)
        } else if self.x < other.x && self.y < other.y {
            Some(Ordering::Less)
        } else if self.x > other.x && self.y > other.y {
            Some(Ordering::Greater)
        } else {
            None
        }
    }
}

impl XY<usize> {
    /// Saturating subtraction. Computes `self - other`, saturating at 0.
    ///
    /// Never panics.
    pub fn saturating_sub<O: Into<Self>>(&self, other: O) -> Self {
        let other = other.into();
        Self::new(self.x.saturating_sub(other.x),
                  self.y.saturating_sub(other.y))
    }

    /// Checked subtraction. Computes `self - other` if possible.
    ///
    /// Returns `None` if `self.x < other.x || self.y < other.y`.
    ///
    /// Never panics.
    pub fn checked_sub<O: Into<Self>>(&self, other: O) -> Option<Self> {
        let other = other.into();
        if self.fits(other) {
            Some(*self - other)
        } else {
            None
        }
    }

    /// Returns a `XY<isize>` from `self`.
    pub fn signed(self) -> XY<isize> {
        self.into()
    }
}

impl<T: Ord> XY<T> {
    /// Returns `true` if `self` could fit inside `other`.
    ///
    /// Shortcut for `self.x <= other.x && self.y <= other.y`.
    ///
    /// If this returns `true`, then `other - self` will not underflow.
    pub fn fits_in<O: Into<Self>>(&self, other: O) -> bool {
        let other = other.into();
        self.x <= other.x && self.y <= other.y
    }

    /// Returns `true` if `other` could fit inside `self`.
    ///
    /// Shortcut for `self.x >= other.x && self.y >= other.y`.
    ///
    /// If this returns `true`, then `self - other` will not underflow.
    pub fn fits<O: Into<Self>>(&self, other: O) -> bool {
        let other = other.into();
        self.x >= other.x && self.y >= other.y
    }

    /// Returns a new Vec2 that is a maximum per coordinate.
    pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, max)
    }

    /// Returns a new Vec2 that is no larger than any input in both dimensions.
    pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, min)
    }

    /// Returns the minimum of `self` and `other`.
    pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
        Self::min(self, other)
    }

    /// Returns the maximum of `self` and `other`.
    pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
        Self::max(self, other)
    }
}

impl<T: Ord + Add<Output = T> + Clone> XY<T> {
    /// Returns (max(self.x,other.x), self.y+other.y)
    pub fn stack_vertical(&self, other: &Self) -> Self {
        Self::new(max(self.x.clone(), other.x.clone()),
                  self.y.clone() + other.y.clone())
    }

    /// Returns (self.x+other.x, max(self.y,other.y))
    pub fn stack_horizontal(&self, other: &Self) -> Self {
        Self::new(self.x.clone() + other.x.clone(),
                  max(self.y.clone(), other.y.clone()))
    }
}

impl<T: Zero + Clone> XY<T> {
    /// Returns a vector with the X component of self, and y=0.
    pub fn keep_x(&self) -> Self {
        Self::new(self.x.clone(), T::zero())
    }

    /// Returns a vector with the Y component of self, and x=0.
    pub fn keep_y(&self) -> Self {
        Self::new(T::zero(), self.y.clone())
    }

    /// Alias for `Self::new(0,0)`.
    pub fn zero() -> Self {
        Self::new(T::zero(), T::zero())
    }
}

impl<T: Into<XY<usize>>> From<T> for XY<isize> {
    fn from(t: T) -> Self {
        let other = t.into();
        Self::new(other.x as isize, other.y as isize)
    }
}

impl From<(i32, i32)> for XY<usize> {
    fn from((x, y): (i32, i32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u32, u32)> for XY<usize> {
    fn from((x, y): (u32, u32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u8, u8)> for XY<usize> {
    fn from((x, y): (u8, u8)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u16, u16)> for XY<usize> {
    fn from((x, y): (u16, u16)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl<T: Add<Output = T>, O: Into<XY<T>>> Add<O> for XY<T> {
    type Output = Self;

    fn add(self, other: O) -> Self {
        self.zip_map(other.into(), Add::add)
    }
}

impl<T: Sub<Output = T>, O: Into<XY<T>>> Sub<O> for XY<T> {
    type Output = Self;

    fn sub(self, other: O) -> Self {
        self.zip_map(other.into(), Sub::sub)
    }
}

impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
    type Output = Self;

    fn div(self, other: T) -> Self {
        self.map(|s| s / other.clone())
    }
}

impl Mul<usize> for XY<usize> {
    type Output = Vec2;

    fn mul(self, other: usize) -> Vec2 {
        self.map(|s| s * other)
    }
}

/// Four values representing each direction.
#[derive(Clone,Copy)]
pub struct Vec4 {
    /// Left margin
    pub left: usize,
    /// Right margin
    pub right: usize,
    /// Top margin
    pub top: usize,
    /// Bottom margin
    pub bottom: usize,
}

impl Vec4 {
    /// Creates a new Vec4.
    pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
        Vec4 {
            left: left,
            right: right,
            top: top,
            bottom: bottom,
        }
    }

    /// Returns left + right.
    pub fn horizontal(&self) -> usize {
        self.left + self.right
    }

    /// Returns top + bottom.
    pub fn vertical(&self) -> usize {
        self.top + self.bottom
    }

    /// Returns (left+right, top+bottom).
    pub fn combined(&self) -> Vec2 {
        Vec2::new(self.horizontal(), self.vertical())
    }

    /// Returns (left, top).
    pub fn top_left(&self) -> Vec2 {
        Vec2::new(self.left, self.top)
    }

    /// Returns (right, bottom).
    pub fn bot_right(&self) -> Vec2 {
        Vec2::new(self.right, self.bottom)
    }
}

impl From<(usize, usize, usize, usize)> for Vec4 {
    fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Vec4 {
        Vec4::new(left, right, top, bottom)
    }
}

impl From<(i32, i32, i32, i32)> for Vec4 {
    fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Vec4 {
        (left as usize, right as usize, top as usize, bottom as usize).into()
    }
}

impl From<((i32, i32), (i32, i32))> for Vec4 {
    fn from(((left, right), (top, bottom)): ((i32, i32), (i32, i32))) -> Vec4 {
        (left, right, top, bottom).into()
    }
}
impl From<((usize, usize), (usize, usize))> for Vec4 {
    fn from(((left, right), (top, bottom)): ((usize, usize), (usize, usize)))
            -> Vec4 {
        (left, right, top, bottom).into()
    }
}

impl<T: Into<Vec4>> Add<T> for Vec4 {
    type Output = Vec4;

    fn add(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left + ov.left,
            right: self.right + ov.right,
            top: self.top + ov.top,
            bottom: self.bottom + ov.bottom,
        }
    }
}

impl<T: Into<Vec4>> Sub<T> for Vec4 {
    type Output = Vec4;

    fn sub(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left - ov.left,
            right: self.right - ov.right,
            top: self.top - ov.top,
            bottom: self.bottom - ov.bottom,
        }
    }
}

impl Div<usize> for Vec4 {
    type Output = Vec4;

    fn div(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left / other,
            right: self.right / other,
            top: self.top / other,
            bottom: self.bottom / other,
        }
    }
}

impl Mul<usize> for Vec4 {
    type Output = Vec4;

    fn mul(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left * other,
            right: self.right * other,
            top: self.top * other,
            bottom: self.bottom * other,
        }
    }
}

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

    #[test]
    fn test_from() {
        let vi32 = Vec2::from((4i32, 5i32));
        let vu32 = Vec2::from((4u32, 5u32));

        let vusize = Vec2::from((4usize, 5usize));
        let vvec = Vec2::from(Vec2::new(4, 5));

        assert_eq!(vi32 - vu32, vusize - vvec);
    }
}
<commit_msg>Add Vec::fits_in_rect<commit_after>//! Points on the 2D character grid.

use XY;
use num::traits::Zero;
use std::cmp::{max, min, Ordering};
use std::ops::{Add, Div, Mul, Sub};

/// Simple 2D size, in cells.
///
/// Note: due to a bug in rustdoc ([#32077]), the documentation for `Vec2` is
/// currently shown on the [`XY`] page.
///
/// [#32077]: https://github.com/rust-lang/rust/issues/32077
/// [`XY`]: ../struct.XY.html
pub type Vec2 = XY<usize>;

impl <T: PartialOrd> PartialOrd for XY<T> {
    /// `a < b` <=> `a.x < b.x && a.y < b.y`
    fn partial_cmp(&self, other: &XY<T>) -> Option<Ordering> {
        if self == other {
            Some(Ordering::Equal)
        } else if self.x < other.x && self.y < other.y {
            Some(Ordering::Less)
        } else if self.x > other.x && self.y > other.y {
            Some(Ordering::Greater)
        } else {
            None
        }
    }
}

impl XY<usize> {
    /// Saturating subtraction. Computes `self - other`, saturating at 0.
    ///
    /// Never panics.
    pub fn saturating_sub<O: Into<Self>>(&self, other: O) -> Self {
        let other = other.into();
        Self::new(
            self.x.saturating_sub(other.x),
            self.y.saturating_sub(other.y),
        )
    }

    /// Checked subtraction. Computes `self - other` if possible.
    ///
    /// Returns `None` if `self.x < other.x || self.y < other.y`.
    ///
    /// Never panics.
    pub fn checked_sub<O: Into<Self>>(&self, other: O) -> Option<Self> {
        let other = other.into();
        if self.fits(other) {
            Some(*self - other)
        } else {
            None
        }
    }

    /// Returns a `XY<isize>` from `self`.
    pub fn signed(self) -> XY<isize> {
        self.into()
    }
}

impl<T: Ord> XY<T> {
    /// Returns `true` if `self` could fit inside `other`.
    ///
    /// Shortcut for `self.x <= other.x && self.y <= other.y`.
    ///
    /// If this returns `true`, then `other - self` will not underflow.
    pub fn fits_in<O: Into<Self>>(&self, other: O) -> bool {
        let other = other.into();
        self.x <= other.x && self.y <= other.y
    }

    /// Returns `true` if `other` could fit inside `self`.
    ///
    /// Shortcut for `self.x >= other.x && self.y >= other.y`.
    ///
    /// If this returns `true`, then `self - other` will not underflow.
    pub fn fits<O: Into<Self>>(&self, other: O) -> bool {
        let other = other.into();
        self.x >= other.x && self.y >= other.y
    }

    /// Returns a new Vec2 that is a maximum per coordinate.
    pub fn max<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, max)
    }

    /// Returns a new Vec2 that is no larger than any input in both dimensions.
    pub fn min<A: Into<XY<T>>, B: Into<XY<T>>>(a: A, b: B) -> Self {
        let a = a.into();
        let b = b.into();
        a.zip_map(b, min)
    }

    /// Returns the minimum of `self` and `other`.
    pub fn or_min<O: Into<XY<T>>>(self, other: O) -> Self {
        Self::min(self, other)
    }

    /// Returns the maximum of `self` and `other`.
    pub fn or_max<O: Into<XY<T>>>(self, other: O) -> Self {
        Self::max(self, other)
    }
}

impl<T: Ord + Add<Output = T> + Clone> XY<T> {
    /// Returns (max(self.x,other.x), self.y+other.y)
    pub fn stack_vertical(&self, other: &Self) -> Self {
        Self::new(
            max(self.x.clone(), other.x.clone()),
            self.y.clone() + other.y.clone(),
        )
    }

    /// Returns (self.x+other.x, max(self.y,other.y))
    pub fn stack_horizontal(&self, other: &Self) -> Self {
        Self::new(
            self.x.clone() + other.x.clone(),
            max(self.y.clone(), other.y.clone()),
        )
    }

    /// Returns `true` if `self` fits in the given rectangle.
    pub fn fits_in_rect<O1, O2>(&self, top_left: O1, size: O2) -> bool
    where
        O1: Into<Self>,
        O2: Into<Self>,
    {
        let top_left = top_left.into();
        self.fits(top_left.clone()) && self < &(top_left + size)
    }
}

impl<T: Zero + Clone> XY<T> {
    /// Returns a vector with the X component of self, and y=0.
    pub fn keep_x(&self) -> Self {
        Self::new(self.x.clone(), T::zero())
    }

    /// Returns a vector with the Y component of self, and x=0.
    pub fn keep_y(&self) -> Self {
        Self::new(T::zero(), self.y.clone())
    }

    /// Alias for `Self::new(0,0)`.
    pub fn zero() -> Self {
        Self::new(T::zero(), T::zero())
    }
}

impl<T: Into<XY<usize>>> From<T> for XY<isize> {
    fn from(t: T) -> Self {
        let other = t.into();
        Self::new(other.x as isize, other.y as isize)
    }
}

impl From<(i32, i32)> for XY<usize> {
    fn from((x, y): (i32, i32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u32, u32)> for XY<usize> {
    fn from((x, y): (u32, u32)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u8, u8)> for XY<usize> {
    fn from((x, y): (u8, u8)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl From<(u16, u16)> for XY<usize> {
    fn from((x, y): (u16, u16)) -> Self {
        (x as usize, y as usize).into()
    }
}

impl<T: Add<Output = T>, O: Into<XY<T>>> Add<O> for XY<T> {
    type Output = Self;

    fn add(self, other: O) -> Self {
        self.zip_map(other.into(), Add::add)
    }
}

impl<T: Sub<Output = T>, O: Into<XY<T>>> Sub<O> for XY<T> {
    type Output = Self;

    fn sub(self, other: O) -> Self {
        self.zip_map(other.into(), Sub::sub)
    }
}

impl<T: Clone + Div<Output = T>> Div<T> for XY<T> {
    type Output = Self;

    fn div(self, other: T) -> Self {
        self.map(|s| s / other.clone())
    }
}

impl Mul<usize> for XY<usize> {
    type Output = Vec2;

    fn mul(self, other: usize) -> Vec2 {
        self.map(|s| s * other)
    }
}

/// Four values representing each direction.
#[derive(Clone, Copy)]
pub struct Vec4 {
    /// Left margin
    pub left: usize,
    /// Right margin
    pub right: usize,
    /// Top margin
    pub top: usize,
    /// Bottom margin
    pub bottom: usize,
}

impl Vec4 {
    /// Creates a new Vec4.
    pub fn new(left: usize, right: usize, top: usize, bottom: usize) -> Self {
        Vec4 {
            left: left,
            right: right,
            top: top,
            bottom: bottom,
        }
    }

    /// Returns left + right.
    pub fn horizontal(&self) -> usize {
        self.left + self.right
    }

    /// Returns top + bottom.
    pub fn vertical(&self) -> usize {
        self.top + self.bottom
    }

    /// Returns (left+right, top+bottom).
    pub fn combined(&self) -> Vec2 {
        Vec2::new(self.horizontal(), self.vertical())
    }

    /// Returns (left, top).
    pub fn top_left(&self) -> Vec2 {
        Vec2::new(self.left, self.top)
    }

    /// Returns (right, bottom).
    pub fn bot_right(&self) -> Vec2 {
        Vec2::new(self.right, self.bottom)
    }
}

impl From<(usize, usize, usize, usize)> for Vec4 {
    fn from((left, right, top, bottom): (usize, usize, usize, usize)) -> Vec4 {
        Vec4::new(left, right, top, bottom)
    }
}

impl From<(i32, i32, i32, i32)> for Vec4 {
    fn from((left, right, top, bottom): (i32, i32, i32, i32)) -> Vec4 {
        (left as usize, right as usize, top as usize, bottom as usize).into()
    }
}

impl From<((i32, i32), (i32, i32))> for Vec4 {
    fn from(((left, right), (top, bottom)): ((i32, i32), (i32, i32))) -> Vec4 {
        (left, right, top, bottom).into()
    }
}
impl From<((usize, usize), (usize, usize))> for Vec4 {
    fn from(
        ((left, right), (top, bottom)): ((usize, usize), (usize, usize))
    ) -> Vec4 {
        (left, right, top, bottom).into()
    }
}

impl<T: Into<Vec4>> Add<T> for Vec4 {
    type Output = Vec4;

    fn add(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left + ov.left,
            right: self.right + ov.right,
            top: self.top + ov.top,
            bottom: self.bottom + ov.bottom,
        }
    }
}

impl<T: Into<Vec4>> Sub<T> for Vec4 {
    type Output = Vec4;

    fn sub(self, other: T) -> Vec4 {
        let ov = other.into();

        Vec4 {
            left: self.left - ov.left,
            right: self.right - ov.right,
            top: self.top - ov.top,
            bottom: self.bottom - ov.bottom,
        }
    }
}

impl Div<usize> for Vec4 {
    type Output = Vec4;

    fn div(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left / other,
            right: self.right / other,
            top: self.top / other,
            bottom: self.bottom / other,
        }
    }
}

impl Mul<usize> for Vec4 {
    type Output = Vec4;

    fn mul(self, other: usize) -> Vec4 {
        Vec4 {
            left: self.left * other,
            right: self.right * other,
            top: self.top * other,
            bottom: self.bottom * other,
        }
    }
}

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

    #[test]
    fn test_from() {
        let vi32 = Vec2::from((4i32, 5i32));
        let vu32 = Vec2::from((4u32, 5u32));

        let vusize = Vec2::from((4usize, 5usize));
        let vvec = Vec2::from(Vec2::new(4, 5));

        assert_eq!(vi32 - vu32, vusize - vvec);
    }
}
<|endoftext|>


<commit_before>// ZFS :: Interface to the `zfs` command line program.
//
// Copyright (c) 2016 by William R. Fraser
//

use std::cmp;
use std::fs;
use std::process::{Child, Command, Stdio};
use std::io::{stdout, Error, Read, Write};
use std::iter::repeat;

use zfs_error::ZfsError;

pub struct ZFS {
    pub use_sudo: bool,
}

fn get_first_column(bytes: &Vec<u8>) -> Vec<String> {
    let mut results: Vec<String> = Vec::new();

    for line in String::from_utf8_lossy(bytes).lines() {
        if !line.trim().is_empty() {
            match line.splitn(2, '\t').next() {
                Some(field) => results.push(String::from(field)),
                None => (),
            }
        }
    }

    results
}

fn read_line<R: Read>(r: &mut R) -> Result<Option<String>, Error> {
    let mut line = String::new();
    loop {
        let mut buf = [0 as u8];
        match r.read(&mut buf) {
            Ok(bytes_read) => {
                if bytes_read == 0 {
                    if line.is_empty() {
                        return Ok(None);
                    } else {
                        return Ok(Some(line));
                    }
                } else if buf[0] == '\n' as u8 {
                    return Ok(Some(line));
                } else {
                    line.push(buf[0] as char);   // we're assuming pure ASCII here.
                }
            }
            Err(e) => return Err(e),
        }
    }
}

fn human_number(n: u64, decimals: usize) -> String {
    if n == 0 {
        return "0".to_string();
    }

    let magnitude = (n as f64).log(1000_f64).floor() as i32;
    if magnitude == 0 {
        return n.to_string();
    }

    let suffixes = ['k', 'M', 'G', 'T', 'P', 'E'];

    let h = (n as f64) / 1000_f64.powi(magnitude);
    format!("{:.*} {}", decimals, h, suffixes[magnitude as usize])
}

impl ZFS {
    fn zfs_command(&self) -> Command {
        if self.use_sudo {
            let mut cmd = Command::new("sudo");
            cmd.arg("zfs");
            cmd
        } else {
            Command::new("zfs")
        }
    }

    fn zfs_list(&self, result_type: &str, dataset: Option<&str>) -> Result<Vec<String>, ZfsError> {
        let mut cmd = self.zfs_command();
        cmd.arg("list").arg("-H").arg("-t").arg(result_type);
        if dataset.is_some() {
            cmd.arg("-r").arg(dataset.unwrap());
        }

        match cmd.output() {
            Err(e) => Err(ZfsError::from(("failed to run 'zfs list'", e))),
            Ok(result) => {
                if !result.status.success() {
                    return Err(ZfsError::from(("failed to run 'zfs list'", &result.stderr)));
                }

                Ok(get_first_column(&result.stdout))
            }
        }
    }

    pub fn volumes(&self, pool: Option<&str>) -> Result<Vec<String>, ZfsError> {
        self.zfs_list("filesystem", pool)
    }

    pub fn snapshots(&self, dataset: Option<&str>) -> Result<Vec<String>, ZfsError> {
        self.zfs_list("snapshot", dataset)
    }

    pub fn send(&self,
                snapshot: &str,
                destination_filename: &str,
                incremental: Option<&str>,
                filter_program: Option<&str>)
                -> Result<(), ZfsError> {

        // This uses 'sh -c' to run the pipeline because it's less work for us.
        // The "$0", "$1", "$2" are replaced by the additional arguments passed to sh.
        // This is nice because it means they can contain any characters and require no escaping.

        let cmdline = (if self.use_sudo {
                          "sudo zfs"
                      } else {
                          "zfs"
                      })
                      .to_owned() + " send -P -v " +
                      incremental.and(Some("-i $0")).or(Some("")).unwrap() +
                      " $1 " +
                      &filter_program.and_then(|f| Some(" | ".to_string() + f))
                                     .or(Some("".to_string()))
                                     .unwrap() + " > $2";
        println!("{}", cmdline);

        let partial_filename = destination_filename.to_string() + "_partial";

        let mut child: Child = zfstry!(Command::new("sh")
            .arg("-c")
            .arg(&cmdline)
            .arg(incremental.or(Some("")).unwrap())
            .arg(snapshot)
            .arg(&partial_filename)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn(), or "failed to run 'zfs send'");

        let mut size: u64 = 0;
        let mut last_line_length: isize = 0;
        loop {
            match read_line(child.stderr.as_mut().unwrap()) {
                Ok(Some(line)) => {
                    if (&line).starts_with("incremental\t") || (&line).starts_with("full\t") {
                        continue;
                    }
                    if (&line).starts_with("size\t") {
                        size = (&line).split_at(5).1.parse::<u64>().unwrap();
                        println!("Full size: {}B", human_number(size, 1));
                        if size == 0 {
                            println!("Empty snapshot; skipping.");
                            break;
                        }
                    } else {
                        let parts: Vec<_> = line.split('\t').collect();
                        if parts.len() != 3 {
                            let msg = format!("Unrecognized output: {}", line);
                            return Err(ZfsError::from(msg));
                        }
                        let percent: f64 = parts[1].parse::<f64>().unwrap() / (size as f64) * 100.;
                        let outline = format!("{} {:.1}% {}B",
                                              parts[0],
                                              percent,
                                              human_number(parts[1].parse::<u64>().unwrap(), 1));
                        let spacing =
                            cmp::max(0, last_line_length - outline.len() as isize) as usize;
                        print!("\r{}{}",
                               outline,
                               repeat(' ').take(spacing).collect::<String>());
                        zfstry!(stdout().flush(), or "failed to flush stdout?!");
                        last_line_length = outline.len() as isize;
                    }
                }
                Ok(None) => break,
                Err(e) => return Err(ZfsError::from(("error reading from 'zfs send' pipeline", e))),
            }
        }

        let exit_status = (&mut child).wait().unwrap();
        if !exit_status.success() {
            let code = exit_status.code().or(Some(0)).unwrap();
            return Err(ZfsError::from(format!("'zfs send' returned nonzero exit code: {}", code)));
        }

        if size == 0 {
            zfstry!(fs::remove_file(&partial_filename), or "failed to remove empty partial file");
        } else {
            zfstry!(fs::rename(&partial_filename, destination_filename), or "failed to move partial file to destination");
        }

        Ok(())
    }
}
<commit_msg>fix fuman_number()<commit_after>// ZFS :: Interface to the `zfs` command line program.
//
// Copyright (c) 2016 by William R. Fraser
//

use std::cmp;
use std::fs;
use std::process::{Child, Command, Stdio};
use std::io::{stdout, Error, Read, Write};
use std::iter::repeat;

use zfs_error::ZfsError;

pub struct ZFS {
    pub use_sudo: bool,
}

fn get_first_column(bytes: &Vec<u8>) -> Vec<String> {
    let mut results: Vec<String> = Vec::new();

    for line in String::from_utf8_lossy(bytes).lines() {
        if !line.trim().is_empty() {
            match line.splitn(2, '\t').next() {
                Some(field) => results.push(String::from(field)),
                None => (),
            }
        }
    }

    results
}

fn read_line<R: Read>(r: &mut R) -> Result<Option<String>, Error> {
    let mut line = String::new();
    loop {
        let mut buf = [0 as u8];
        match r.read(&mut buf) {
            Ok(bytes_read) => {
                if bytes_read == 0 {
                    if line.is_empty() {
                        return Ok(None);
                    } else {
                        return Ok(Some(line));
                    }
                } else if buf[0] == '\n' as u8 {
                    return Ok(Some(line));
                } else {
                    line.push(buf[0] as char);   // we're assuming pure ASCII here.
                }
            }
            Err(e) => return Err(e),
        }
    }
}

fn human_number(n: u64, decimals: usize) -> String {
    if n == 0 {
        return "0".to_string();
    }

    let magnitude = (n as f64).log(1000_f64).floor() as i32;
    if magnitude == 0 {
        return n.to_string();
    }

    let suffixes = ['k', 'M', 'G', 'T', 'P', 'E'];

    let h = (n as f64) / 1000_f64.powi(magnitude);
    if magnitude > 0 {
        format!("{:.*} {}", decimals, h, suffixes[magnitude as usize - 1])
    }
    else {
        h.to_string()
    }
}

#[test]
fn test_human_number() {
    assert_eq!(human_number(            1, 1), "1");
    assert_eq!(human_number(          999, 1), "999");
    assert_eq!(human_number(         1000, 1), "1.0 k");
    assert_eq!(human_number(         1500, 1), "1.5 k");
    assert_eq!(human_number(       999900, 1), "999.9 k");
    assert_eq!(human_number(      1000000, 1), "1.0 M");
    assert_eq!(human_number(   1000000000, 1), "1.0 G");
    assert_eq!(human_number(1000000000000, 1), "1.0 T");
}

impl ZFS {
    fn zfs_command(&self) -> Command {
        if self.use_sudo {
            let mut cmd = Command::new("sudo");
            cmd.arg("zfs");
            cmd
        } else {
            Command::new("zfs")
        }
    }

    fn zfs_list(&self, result_type: &str, dataset: Option<&str>) -> Result<Vec<String>, ZfsError> {
        let mut cmd = self.zfs_command();
        cmd.arg("list").arg("-H").arg("-t").arg(result_type);
        if dataset.is_some() {
            cmd.arg("-r").arg(dataset.unwrap());
        }

        match cmd.output() {
            Err(e) => Err(ZfsError::from(("failed to run 'zfs list'", e))),
            Ok(result) => {
                if !result.status.success() {
                    return Err(ZfsError::from(("failed to run 'zfs list'", &result.stderr)));
                }

                Ok(get_first_column(&result.stdout))
            }
        }
    }

    pub fn volumes(&self, pool: Option<&str>) -> Result<Vec<String>, ZfsError> {
        self.zfs_list("filesystem", pool)
    }

    pub fn snapshots(&self, dataset: Option<&str>) -> Result<Vec<String>, ZfsError> {
        self.zfs_list("snapshot", dataset)
    }

    pub fn send(&self,
                snapshot: &str,
                destination_filename: &str,
                incremental: Option<&str>,
                filter_program: Option<&str>)
                -> Result<(), ZfsError> {

        // This uses 'sh -c' to run the pipeline because it's less work for us.
        // The "$0", "$1", "$2" are replaced by the additional arguments passed to sh.
        // This is nice because it means they can contain any characters and require no escaping.

        let cmdline = (if self.use_sudo {
                          "sudo zfs"
                      } else {
                          "zfs"
                      })
                      .to_owned() + " send -P -v " +
                      incremental.and(Some("-i $0")).or(Some("")).unwrap() +
                      " $1 " +
                      &filter_program.and_then(|f| Some(" | ".to_string() + f))
                                     .or(Some("".to_string()))
                                     .unwrap() + " > $2";

        let partial_filename = destination_filename.to_string() + "_partial";

        let mut child: Child = zfstry!(Command::new("sh")
            .arg("-c")
            .arg(&cmdline)
            .arg(incremental.or(Some("")).unwrap())
            .arg(snapshot)
            .arg(&partial_filename)
            .stdin(Stdio::inherit())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn(), or "failed to run 'zfs send'");

        let mut size: u64 = 0;
        let mut last_line_length: isize = 0;
        loop {
            match read_line(child.stderr.as_mut().unwrap()) {
                Ok(Some(line)) => {
                    if (&line).starts_with("incremental\t") || (&line).starts_with("full\t") {
                        continue;
                    }
                    if (&line).starts_with("size\t") {
                        size = (&line).split_at(5).1.parse::<u64>().unwrap();
                        println!("Full size: {}B", human_number(size, 1));
                        if size == 0 {
                            println!("Empty snapshot; skipping.");
                            break;
                        }
                    } else {
                        let parts: Vec<_> = line.split('\t').collect();
                        if parts.len() != 3 {
                            let msg = format!("Unrecognized output: {}", line);
                            return Err(ZfsError::from(msg));
                        }
                        let percent: f64 = parts[1].parse::<f64>().unwrap() / (size as f64) * 100.;
                        let outline = format!("{} {:.1}% {}B",
                                              parts[0],
                                              percent,
                                              human_number(parts[1].parse::<u64>().unwrap(), 1));
                        let spacing =
                            cmp::max(0, last_line_length - outline.len() as isize) as usize;
                        print!("\r{}{}",
                               outline,
                               repeat(' ').take(spacing).collect::<String>());
                        zfstry!(stdout().flush(), or "failed to flush stdout?!");
                        last_line_length = outline.len() as isize;
                    }
                }
                Ok(None) => break,
                Err(e) => return Err(ZfsError::from(("error reading from 'zfs send' pipeline", e))),
            }
        }

        let exit_status = (&mut child).wait().unwrap();
        if !exit_status.success() {
            let code = exit_status.code().or(Some(0)).unwrap();
            return Err(ZfsError::from(format!("'zfs send' returned nonzero exit code: {}", code)));
        }

        if size == 0 {
            zfstry!(fs::remove_file(&partial_filename), or "failed to remove empty partial file");
        } else {
            zfstry!(fs::rename(&partial_filename, destination_filename), or "failed to move partial file to destination");
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(core)]

extern crate rustc_serialize as rustc_serialize;

extern crate unix_socket;
extern crate libc;

#[macro_use]
extern crate urpc;

use std::intrinsics;
use unix_socket::UnixStream;

urpc! {
    pub interface oops {
        fn oops(x: u8) -> u8 {}
    }
}

struct Whoops;

impl oops::Methods for Whoops {
    fn oops(&mut self, x: u8) -> urpc::Result<u8> {
        assert_eq!(x, 42);
        unsafe {
            intrinsics::volatile_set_memory(0 as *mut u8, 0, 1 << 32);
        }
        Ok(0) // yeah right
    }
}

#[test]
fn server_crash() {
    use oops::Methods;

    let (s1, s2) = UnixStream::unnamed().unwrap();

    let pid = unsafe { libc::fork() };
    assert!(pid >= 0);

    match pid {
        0 => {
            drop(s2);
            oops::serve(Whoops, s1).unwrap();
        }
        _ => {
            drop(s1);
            let mut client = oops::Client::new(s2);
            assert!(client.oops(42).is_err());
        }
    }
}
<commit_msg>Fix server-crash test again<commit_after>extern crate rustc_serialize as rustc_serialize;

extern crate unix_socket;
extern crate libc;

#[macro_use]
extern crate urpc;

use unix_socket::UnixStream;

urpc! {
    pub interface oops {
        fn oops(x: u8) -> u8 {}
    }
}

struct Whoops;

impl oops::Methods for Whoops {
    fn oops(&mut self, x: u8) -> urpc::Result<u8> {
        assert_eq!(x, 42);

        // Deliberately crash the server.  Can't do this in a single statement,
        // since the compiler yells at us.
        let zero = 0;
        let _: i32 = 1 / zero;

        Ok(0) // yeah right
    }
}

#[test]
fn server_crash() {
    use oops::Methods;

    let (s1, s2) = UnixStream::unnamed().unwrap();

    let pid = unsafe { libc::fork() };
    assert!(pid >= 0);

    match pid {
        0 => {
            drop(s2);
            oops::serve(Whoops, s1).unwrap();
        }
        _ => {
            drop(s1);
            let mut client = oops::Client::new(s2);
            assert!(client.oops(42).is_err());
        }
    }
}
<|endoftext|>


<commit_before>//! Simple websocket client.

#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;

use std::{io, thread};
use std::time::Duration;

use actix::*;
use futures::Future;
use actix_web::ws::{Message, WsClientError, WsClient, WsClientWriter};

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _ = env_logger::init();
    let sys = actix::System::new("ws-example");

    Arbiter::handle().spawn(
        WsClient::new("http://127.0.0.1:8080/ws/")
            .connect().unwrap()
            .map_err(|e| {
                println!("Error: {}", e);
                ()
            })
            .map(|(reader, writer)| {
                let addr: Addr<Syn, _> = ChatClient::create(|ctx| {
                    ChatClient::add_stream(reader, ctx);
                    ChatClient(writer)
                });

                // start console loop
                thread::spawn(move|| {
                    loop {
                        let mut cmd = String::new();
                        if io::stdin().read_line(&mut cmd).is_err() {
                            println!("error");
                            return
                        }
                        addr.do_send(ClientCommand(cmd));
                    }
                });

                ()
            })
    );

    let _ = sys.run();
}

struct ChatClient(WsClientWriter);

#[derive(Message)]
struct ClientCommand(String);

impl Actor for ChatClient {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Context<Self>) {
        // start heartbeats otherwise server will disconnect after 10 seconds
        self.hb(ctx)
    }

    fn stopped(&mut self, _: &mut Context<Self>) {
        println!("Disconnected");

        // Stop application on disconnect
        Arbiter::system().do_send(actix::msgs::SystemExit(0));
    }
}

impl ChatClient {
    fn hb(&self, ctx: &mut Context<Self>) {
        ctx.run_later(Duration::new(1, 0), |act, ctx| {
            act.0.ping("");
            act.hb(ctx);
        });
    }
}

/// Handle stdin commands
impl Handler<ClientCommand> for ChatClient {
    type Result = ();

    fn handle(&mut self, msg: ClientCommand, ctx: &mut Context<Self>) {
        self.0.text(msg.0.as_str())
    }
}

/// Handle server websocket messages
impl StreamHandler<Message, WsClientError> for ChatClient {

    fn handle(&mut self, msg: Message, ctx: &mut Context<Self>) {
        match msg {
            Message::Text(txt) => println!("Server: {:?}", txt),
            _ => ()
        }
    }

    fn started(&mut self, ctx: &mut Context<Self>) {
        println!("Connected");
    }

    fn finished(&mut self, ctx: &mut Context<Self>) {
        println!("Server disconnected");
        ctx.stop()
    }
}
<commit_msg>fix websocket example<commit_after>//! Simple websocket client.

#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;

use std::{io, thread};
use std::time::Duration;

use actix::*;
use futures::Future;
use actix_web::ws::{Message, WsClientError, WsClient, WsClientWriter};

fn main() {
    ::std::env::set_var("RUST_LOG", "actix_web=info");
    let _ = env_logger::init();
    let sys = actix::System::new("ws-example");

    Arbiter::handle().spawn(
        WsClient::new("http://127.0.0.1:8080/ws/")
            .connect()
            .map_err(|e| {
                println!("Error: {}", e);
                ()
            })
            .map(|(reader, writer)| {
                let addr: Addr<Syn, _> = ChatClient::create(|ctx| {
                    ChatClient::add_stream(reader, ctx);
                    ChatClient(writer)
                });

                // start console loop
                thread::spawn(move|| {
                    loop {
                        let mut cmd = String::new();
                        if io::stdin().read_line(&mut cmd).is_err() {
                            println!("error");
                            return
                        }
                        addr.do_send(ClientCommand(cmd));
                    }
                });

                ()
            })
    );

    let _ = sys.run();
}

struct ChatClient(WsClientWriter);

#[derive(Message)]
struct ClientCommand(String);

impl Actor for ChatClient {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Context<Self>) {
        // start heartbeats otherwise server will disconnect after 10 seconds
        self.hb(ctx)
    }

    fn stopped(&mut self, _: &mut Context<Self>) {
        println!("Disconnected");

        // Stop application on disconnect
        Arbiter::system().do_send(actix::msgs::SystemExit(0));
    }
}

impl ChatClient {
    fn hb(&self, ctx: &mut Context<Self>) {
        ctx.run_later(Duration::new(1, 0), |act, ctx| {
            act.0.ping("");
            act.hb(ctx);
        });
    }
}

/// Handle stdin commands
impl Handler<ClientCommand> for ChatClient {
    type Result = ();

    fn handle(&mut self, msg: ClientCommand, ctx: &mut Context<Self>) {
        self.0.text(msg.0.as_str())
    }
}

/// Handle server websocket messages
impl StreamHandler<Message, WsClientError> for ChatClient {

    fn handle(&mut self, msg: Message, ctx: &mut Context<Self>) {
        match msg {
            Message::Text(txt) => println!("Server: {:?}", txt),
            _ => ()
        }
    }

    fn started(&mut self, ctx: &mut Context<Self>) {
        println!("Connected");
    }

    fn finished(&mut self, ctx: &mut Context<Self>) {
        println!("Server disconnected");
        ctx.stop()
    }
}
<|endoftext|>