<commit_before>//! A generic connection pool.
//!
//! Opening a new database connection every time one is needed is both
//! inefficient and can lead to resource exhaustion under high traffic
//! conditions. A connection pool maintains a set of open connections to a
//! database, handing them out for repeated use.
//!
//! r2d2 is agnostic to the connection type it is managing. Implementors of the
//! `ManageConnection` trait provide the database-specific logic to create and
//! check the health of connections.
//!
//! # Example
//!
//! Using an imaginary "foodb" database.
//!
//! ```rust,ignore
//! use std::thread;
//!
//! extern crate r2d2;
//! extern crate r2d2_foodb;
//!
//! fn main() {
//!     let config = r2d2::Config::builder()
//!         .pool_size(15)
//!         .error_handler(Box::new(r2d2::LoggingErrorHandler))
//!         .build();
//!     let manager = r2d2_foodb::FooConnectionManager::new("localhost:1234");
//!
//!     let pool = r2d2::Pool::new(config, manager).unwrap();
//!
//!     for _ in 0..20 {
//!         let pool = pool.clone();
//!         thread::spawn(move || {
//!             let conn = pool.get().unwrap();
//!             // use the connection
//!             // it will be returned to the pool when it falls out of scope.
//!         })
//!     }
//! }
//! ```
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/r2d2/doc/v0.6.2")]

#[macro_use]
extern crate log;
extern crate time;

use std::cmp;
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::sync::{Arc, Mutex, Condvar};
use time::{Duration, SteadyTime};

#[doc(inline)]
pub use config::Config;

use task::ScheduledThreadPool;

pub mod config;
mod task;
mod thunk;

#[cfg(test)]
mod test;

/// A trait which provides connection-specific functionality.
pub trait ManageConnection: Send + Sync + 'static {
    /// The connection type this manager deals with.
    type Connection: Send + 'static;

    /// The error type returned by `Connection`s.
    type Error: 'static;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ManageConnection`.
pub trait HandleError<E>: Send+Sync+'static {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// A `HandleError` implementation which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopErrorHandler;

impl<E> HandleError<E> for NopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// A `HandleError` implementation which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> HandleError<E> for LoggingErrorHandler where E: Error
{
    fn handle_error(&self, error: E) {
        error!("{}", error);
    }
}

/// A trait which allows for customization of connections.
pub trait CustomizeConnection<C, E>: Send+Sync+'static {
    /// Called with connections immediately after they are returned from
    /// `ManageConnection::connect`.
    ///
    /// The default implementation simply returns `Ok(())`.
    ///
    /// # Errors
    ///
    /// If this method returns an error, the connection will be discarded.
    #[allow(unused_variables)]
    fn on_acquire(&self, conn: &mut C) -> Result<(), E> {
        Ok(())
    }
}

/// A `CustomizeConnection` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopConnectionCustomizer;

impl<C, E> CustomizeConnection<C, E> for NopConnectionCustomizer {}

struct Conn<C> {
    conn: C,
    birth: SteadyTime,
    idle_start: SteadyTime,
}

impl<C> Conn<C> {
    fn new(conn: C) -> Conn<C> {
        let now = SteadyTime::now();
        Conn {
            conn: conn,
            birth: now,
            idle_start: now,
        }
    }
}

struct PoolInternals<C> {
    conns: VecDeque<Conn<C>>,
    num_conns: u32,
    pending_conns: u32,
}

struct SharedPool<M>
    where M: ManageConnection
{
    config: Config<M::Connection, M::Error>,
    manager: M,
    internals: Mutex<PoolInternals<M::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

impl<M> Drop for SharedPool<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.thread_pool.clear();
    }
}

fn drop_conn<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.num_conns -= 1;

    let min = shared.config.min_idle().unwrap_or(shared.config.pool_size());
    if internals.num_conns + internals.pending_conns < min {
        add_connection(shared, internals);
    }
}

fn add_connection<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.pending_conns += 1;
    inner(Duration::zero(), shared);

    fn inner<M>(delay: Duration, shared: &Arc<SharedPool<M>>)
        where M: ManageConnection
    {
        let new_shared = shared.clone();
        shared.thread_pool.run_after(delay, move || {
            let shared = new_shared;
            let conn = shared.manager.connect().and_then(|mut conn| {
                shared.config.connection_customizer().on_acquire(&mut conn).map(|_| conn)
            });
            match conn {
                Ok(conn) => {
                    let mut internals = shared.internals.lock().unwrap();
                    internals.conns.push_back(Conn::new(conn));
                    internals.pending_conns -= 1;
                    internals.num_conns += 1;
                    shared.cond.notify_one();
                }
                Err(err) => {
                    shared.config.error_handler().handle_error(err);
                    let delay = cmp::max(Duration::milliseconds(200), delay);
                    let delay = cmp::min(cvt(shared.config.connection_timeout()) / 2, delay * 2);
                    inner(delay, &shared);
                }
            }
        });
    }
}

fn reap_connections<M>(shared: &Arc<SharedPool<M>>)
    where M: ManageConnection
{
    let mut old = VecDeque::with_capacity(shared.config.pool_size() as usize);
    let mut to_drop = vec![];

    let mut internals = shared.internals.lock().unwrap();
    mem::swap(&mut old, &mut internals.conns);
    let now = SteadyTime::now();
    for conn in old {
        let mut reap = false;
        if let Some(timeout) = shared.config.idle_timeout() {
            reap |= now - conn.idle_start >= cvt(timeout);
        }
        if let Some(lifetime) = shared.config.max_lifetime() {
            reap |= now - conn.birth >= cvt(lifetime);
        }
        if reap {
            drop_conn(shared, &mut internals);
            to_drop.push(conn.conn);
        } else {
            internals.conns.push_back(conn);
        }
    }
    drop(internals); // make sure we run to_drop destructors without this locked
}

/// A generic connection pool.
pub struct Pool<M>
    where M: ManageConnection
{
    shared: Arc<SharedPool<M>>,
}

/// Returns a new `Pool` referencing the same state as `self`.
impl<M> Clone for Pool<M> where M: ManageConnection
{
    fn clone(&self) -> Pool<M> {
        Pool { shared: self.shared.clone() }
    }
}

impl<M> fmt::Debug for Pool<M> where M: ManageConnection + fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let inner = self.shared.internals.lock().unwrap();

        fmt.debug_struct("Pool")
           .field("connections", &inner.num_conns)
           .field("idle_connections", &inner.conns.len())
           .field("config", &self.shared.config)
           .field("manager", &self.shared.manager)
           .finish()
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError(());

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout(());

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ManageConnection
{
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    pub fn new(config: Config<M::Connection, M::Error>,
               manager: M)
               -> Result<Pool<M>, InitializationError> {
        Pool::new_inner(config, manager, 30)
    }

    // for testing
    fn new_inner(config: Config<M::Connection, M::Error>,
                 manager: M,
                 reaper_rate: i64)
                 -> Result<Pool<M>, InitializationError> {
        let internals = PoolInternals {
            conns: VecDeque::with_capacity(config.pool_size() as usize),
            num_conns: 0,
            pending_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            thread_pool: ScheduledThreadPool::new(config.helper_threads() as usize),
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        let initial_size = shared.config.min_idle().unwrap_or(shared.config.pool_size());
        {
            let mut inner = shared.internals.lock().unwrap();
            for _ in 0..initial_size {
                add_connection(&shared, &mut inner);
            }
            drop(inner);
        }

        if shared.config.initialization_fail_fast() {
            let end = SteadyTime::now() + cvt(shared.config.connection_timeout());
            let mut internals = shared.internals.lock().unwrap();

            while internals.num_conns != initial_size {
                let wait = end - SteadyTime::now();
                if wait <= Duration::zero() {
                    return Err(InitializationError(()));
                }
                internals = shared.cond
                                  .wait_timeout_ms(internals, wait.num_milliseconds() as u32)
                                  .unwrap()
                                  .0;
            }
        }

        if shared.config.max_lifetime().is_some() || shared.config.idle_timeout().is_some() {
            let s = shared.clone();
            shared.thread_pool
                  .run_at_fixed_rate(Duration::seconds(reaper_rate), move || reap_connections(&s));
        }

        Ok(Pool { shared: shared })
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get(&self) -> Result<PooledConnection<M>, GetTimeout> {
        let end = SteadyTime::now() + cvt(self.shared.config.connection_timeout());
        let mut internals = self.shared.internals.lock().unwrap();

        let connection;
        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out() {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn.conn) {
                            self.shared.config.error_handler().handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            drop_conn(&self.shared, &mut internals);
                            continue;
                        }
                    }

                    connection = conn;
                    break;
                }
                None => {
                    if internals.num_conns + internals.pending_conns <
                       self.shared.config.pool_size() {
                        add_connection(&self.shared, &mut internals);
                    }

                    let now = SteadyTime::now();
                    let timeout = (end - now).num_milliseconds();
                    if timeout <= 0 {
                        return Err(GetTimeout(()));
                    };
                    internals = self.shared
                                    .cond
                                    .wait_timeout_ms(internals, timeout as u32)
                                    .unwrap()
                                    .0;
                }
            }
        }

        Ok(PooledConnection {
            pool: self.clone(),
            conn: Some(connection),
        })
    }

    fn put_back(&self, mut conn: Conn<M::Connection>) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn.conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            drop_conn(&self.shared, &mut internals);
        } else {
            conn.idle_start = SteadyTime::now();
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M>
    where M: ManageConnection
{
    pool: Pool<M>,
    conn: Option<Conn<M::Connection>>,
}

impl<M> fmt::Debug for PooledConnection<M>
    where M: ManageConnection,
          M::Connection: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.conn.as_ref().unwrap().conn, fmt)
    }
}

impl<M> Drop for PooledConnection<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M> where M: ManageConnection
{
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        &self.conn.as_ref().unwrap().conn
    }
}

impl<M> DerefMut for PooledConnection<M> where M: ManageConnection
{
    fn deref_mut(&mut self) -> &mut M::Connection {
        &mut self.conn.as_mut().unwrap().conn
    }
}

fn cvt(d: std::time::Duration) -> Duration {
    Duration::seconds(d.as_secs() as i64) + Duration::nanoseconds(d.subsec_nanos() as i64)
}
<commit_msg>Cleanup<commit_after>//! A generic connection pool.
//!
//! Opening a new database connection every time one is needed is both
//! inefficient and can lead to resource exhaustion under high traffic
//! conditions. A connection pool maintains a set of open connections to a
//! database, handing them out for repeated use.
//!
//! r2d2 is agnostic to the connection type it is managing. Implementors of the
//! `ManageConnection` trait provide the database-specific logic to create and
//! check the health of connections.
//!
//! # Example
//!
//! Using an imaginary "foodb" database.
//!
//! ```rust,ignore
//! use std::thread;
//!
//! extern crate r2d2;
//! extern crate r2d2_foodb;
//!
//! fn main() {
//!     let config = r2d2::Config::builder()
//!         .pool_size(15)
//!         .error_handler(Box::new(r2d2::LoggingErrorHandler))
//!         .build();
//!     let manager = r2d2_foodb::FooConnectionManager::new("localhost:1234");
//!
//!     let pool = r2d2::Pool::new(config, manager).unwrap();
//!
//!     for _ in 0..20 {
//!         let pool = pool.clone();
//!         thread::spawn(move || {
//!             let conn = pool.get().unwrap();
//!             // use the connection
//!             // it will be returned to the pool when it falls out of scope.
//!         })
//!     }
//! }
//! ```
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/r2d2/doc/v0.6.2")]

#[macro_use]
extern crate log;
extern crate time;

use std::cmp;
use std::collections::VecDeque;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::sync::{Arc, Mutex, Condvar};
use time::{Duration, SteadyTime};

#[doc(inline)]
pub use config::Config;

use task::ScheduledThreadPool;

pub mod config;
mod task;
mod thunk;

#[cfg(test)]
mod test;

/// A trait which provides connection-specific functionality.
pub trait ManageConnection: Send + Sync + 'static {
    /// The connection type this manager deals with.
    type Connection: Send + 'static;

    /// The error type returned by `Connection`s.
    type Error: 'static;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ManageConnection`.
pub trait HandleError<E>: Send+Sync+'static {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// A `HandleError` implementation which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopErrorHandler;

impl<E> HandleError<E> for NopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// A `HandleError` implementation which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> HandleError<E> for LoggingErrorHandler where E: Error
{
    fn handle_error(&self, error: E) {
        error!("{}", error);
    }
}

/// A trait which allows for customization of connections.
pub trait CustomizeConnection<C, E>: Send+Sync+'static {
    /// Called with connections immediately after they are returned from
    /// `ManageConnection::connect`.
    ///
    /// The default implementation simply returns `Ok(())`.
    ///
    /// # Errors
    ///
    /// If this method returns an error, the connection will be discarded.
    #[allow(unused_variables)]
    fn on_acquire(&self, conn: &mut C) -> Result<(), E> {
        Ok(())
    }
}

/// A `CustomizeConnection` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NopConnectionCustomizer;

impl<C, E> CustomizeConnection<C, E> for NopConnectionCustomizer {}

struct Conn<C> {
    conn: C,
    birth: SteadyTime,
    idle_start: SteadyTime,
}

impl<C> Conn<C> {
    fn new(conn: C) -> Conn<C> {
        let now = SteadyTime::now();
        Conn {
            conn: conn,
            birth: now,
            idle_start: now,
        }
    }
}

struct PoolInternals<C> {
    conns: VecDeque<Conn<C>>,
    num_conns: u32,
    pending_conns: u32,
}

struct SharedPool<M>
    where M: ManageConnection
{
    config: Config<M::Connection, M::Error>,
    manager: M,
    internals: Mutex<PoolInternals<M::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

impl<M> Drop for SharedPool<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.thread_pool.clear();
    }
}

fn drop_conn<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.num_conns -= 1;

    let min = shared.config.min_idle().unwrap_or(shared.config.pool_size());
    if internals.num_conns + internals.pending_conns < min {
        add_connection(shared, internals);
    }
}

fn add_connection<M>(shared: &Arc<SharedPool<M>>, internals: &mut PoolInternals<M::Connection>)
    where M: ManageConnection
{
    internals.pending_conns += 1;
    inner(Duration::zero(), shared);

    fn inner<M>(delay: Duration, shared: &Arc<SharedPool<M>>)
        where M: ManageConnection
    {
        let new_shared = shared.clone();
        shared.thread_pool.run_after(delay, move || {
            let shared = new_shared;
            let conn = shared.manager.connect().and_then(|mut conn| {
                shared.config.connection_customizer().on_acquire(&mut conn).map(|_| conn)
            });
            match conn {
                Ok(conn) => {
                    let mut internals = shared.internals.lock().unwrap();
                    internals.conns.push_back(Conn::new(conn));
                    internals.pending_conns -= 1;
                    internals.num_conns += 1;
                    shared.cond.notify_one();
                }
                Err(err) => {
                    shared.config.error_handler().handle_error(err);
                    let delay = cmp::max(Duration::milliseconds(200), delay);
                    let delay = cmp::min(cvt(shared.config.connection_timeout()) / 2, delay * 2);
                    inner(delay, &shared);
                }
            }
        });
    }
}

fn reap_connections<M>(shared: &Arc<SharedPool<M>>)
    where M: ManageConnection
{
    let mut old = VecDeque::with_capacity(shared.config.pool_size() as usize);
    let mut to_drop = vec![];

    let mut internals = shared.internals.lock().unwrap();
    mem::swap(&mut old, &mut internals.conns);
    let now = SteadyTime::now();
    for conn in old {
        let mut reap = false;
        if let Some(timeout) = shared.config.idle_timeout() {
            reap |= now - conn.idle_start >= cvt(timeout);
        }
        if let Some(lifetime) = shared.config.max_lifetime() {
            reap |= now - conn.birth >= cvt(lifetime);
        }
        if reap {
            drop_conn(shared, &mut internals);
            to_drop.push(conn.conn);
        } else {
            internals.conns.push_back(conn);
        }
    }
    drop(internals); // make sure we run to_drop destructors without this locked
}

/// A generic connection pool.
pub struct Pool<M>
    where M: ManageConnection
{
    shared: Arc<SharedPool<M>>,
}

/// Returns a new `Pool` referencing the same state as `self`.
impl<M> Clone for Pool<M> where M: ManageConnection
{
    fn clone(&self) -> Pool<M> {
        Pool { shared: self.shared.clone() }
    }
}

impl<M> fmt::Debug for Pool<M> where M: ManageConnection + fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let inner = self.shared.internals.lock().unwrap();

        fmt.debug_struct("Pool")
           .field("connections", &inner.num_conns)
           .field("idle_connections", &inner.conns.len())
           .field("config", &self.shared.config)
           .field("manager", &self.shared.manager)
           .finish()
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError(());

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout(());

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ManageConnection
{
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    pub fn new(config: Config<M::Connection, M::Error>,
               manager: M)
               -> Result<Pool<M>, InitializationError> {
        Pool::new_inner(config, manager, 30)
    }

    // for testing
    fn new_inner(config: Config<M::Connection, M::Error>,
                 manager: M,
                 reaper_rate: i64)
                 -> Result<Pool<M>, InitializationError> {
        let internals = PoolInternals {
            conns: VecDeque::with_capacity(config.pool_size() as usize),
            num_conns: 0,
            pending_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            thread_pool: ScheduledThreadPool::new(config.helper_threads() as usize),
            config: config,
            manager: manager,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
        });

        let initial_size = shared.config.min_idle().unwrap_or(shared.config.pool_size());
        {
            let mut inner = shared.internals.lock().unwrap();
            for _ in 0..initial_size {
                add_connection(&shared, &mut inner);
            }
            drop(inner);
        }

        if shared.config.initialization_fail_fast() {
            let end = SteadyTime::now() + cvt(shared.config.connection_timeout());
            let mut internals = shared.internals.lock().unwrap();

            while internals.num_conns != initial_size {
                let wait = end - SteadyTime::now();
                if wait <= Duration::zero() {
                    return Err(InitializationError(()));
                }
                internals = shared.cond
                                  .wait_timeout_ms(internals, wait.num_milliseconds() as u32)
                                  .unwrap()
                                  .0;
            }
        }

        if shared.config.max_lifetime().is_some() || shared.config.idle_timeout().is_some() {
            let s = shared.clone();
            shared.thread_pool
                  .run_at_fixed_rate(Duration::seconds(reaper_rate), move || reap_connections(&s));
        }

        Ok(Pool { shared: shared })
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get(&self) -> Result<PooledConnection<M>, GetTimeout> {
        let end = SteadyTime::now() + cvt(self.shared.config.connection_timeout());
        let mut internals = self.shared.internals.lock().unwrap();

        let connection;
        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out() {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn.conn) {
                            self.shared.config.error_handler().handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            drop_conn(&self.shared, &mut internals);
                            continue;
                        }
                    }

                    connection = conn;
                    break;
                }
                None => {
                    if internals.num_conns + internals.pending_conns <
                       self.shared.config.pool_size() {
                        add_connection(&self.shared, &mut internals);
                    }

                    let wait = end - SteadyTime::now();
                    if wait <= Duration::zero() {
                        return Err(GetTimeout(()));
                    };
                    internals = self.shared
                                    .cond
                                    .wait_timeout_ms(internals, wait.num_milliseconds() as u32)
                                    .unwrap()
                                    .0;
                }
            }
        }

        Ok(PooledConnection {
            pool: self.clone(),
            conn: Some(connection),
        })
    }

    fn put_back(&self, mut conn: Conn<M::Connection>) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn.conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            drop_conn(&self.shared, &mut internals);
        } else {
            conn.idle_start = SteadyTime::now();
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<M>
    where M: ManageConnection
{
    pool: Pool<M>,
    conn: Option<Conn<M::Connection>>,
}

impl<M> fmt::Debug for PooledConnection<M>
    where M: ManageConnection,
          M::Connection: fmt::Debug
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.conn.as_ref().unwrap().conn, fmt)
    }
}

impl<M> Drop for PooledConnection<M> where M: ManageConnection
{
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<M> Deref for PooledConnection<M> where M: ManageConnection
{
    type Target = M::Connection;

    fn deref(&self) -> &M::Connection {
        &self.conn.as_ref().unwrap().conn
    }
}

impl<M> DerefMut for PooledConnection<M> where M: ManageConnection
{
    fn deref_mut(&mut self) -> &mut M::Connection {
        &mut self.conn.as_mut().unwrap().conn
    }
}

fn cvt(d: std::time::Duration) -> Duration {
    Duration::seconds(d.as_secs() as i64) + Duration::nanoseconds(d.subsec_nanos() as i64)
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc.
//
// 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.

pub mod batch_iterator;
pub mod color;
pub mod data_provider;
pub mod errors;
pub mod math;
pub mod octree;
pub mod read_write;
pub mod s2_cells;

use cgmath::Vector3;
use std::collections::BTreeMap;

// Version 9 -> 10: Change in NodeId proto from level (u8) and index (u64) to high (u64) and low
// (u64). We are able to convert the proto on read, so the tools can still read version 9.
// Version 10 -> 11: Change in AxisAlignedCuboid proto from Vector3f min/max to Vector3d min/max.
// We are able to convert the proto on read, so the tools can still read version 9/10.
// Version 11 -> 12: Change in Meta names and structures, to allow both s2 and octree meta.
// We are able to convert the proto on read, so the tools can still read version 9/10/11.
pub const CURRENT_VERSION: i32 = 12;

#[derive(Debug, Clone)]
pub struct Point {
    pub position: cgmath::Vector3<f64>,
    // TODO(sirver): Make color optional, we might not always have it.
    pub color: color::Color<u8>,

    // The intensity of the point if it exists. This value is usually handed through directly by a
    // sensor and has therefore no defined range - or even meaning.
    pub intensity: Option<f32>,
}

pub fn attribute_extension(attribute: &str) -> &str {
    match attribute {
        "position" => "xyz",
        "color" => "rgb",
        _ => attribute,
    }
}

/// General field to describe point feature attributes such as color, intensity, ...
#[derive(Debug, Clone)]
pub enum AttributeData {
    U8(Vec<u8>),
    I64(Vec<i64>),
    U64(Vec<u64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    U8Vec3(Vec<Vector3<u8>>),
    F64Vec3(Vec<Vector3<f64>>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttributeDataType {
    U8,
    I64,
    U64,
    F32,
    F64,
    U8Vec3,
    F64Vec3,
}

impl AttributeDataType {
    pub fn to_proto(&self) -> proto::AttributeDataType {
        match self {
            AttributeDataType::U8 => proto::AttributeDataType::U8,
            AttributeDataType::I64 => proto::AttributeDataType::I64,
            AttributeDataType::U64 => proto::AttributeDataType::U64,
            AttributeDataType::F32 => proto::AttributeDataType::F32,
            AttributeDataType::F64 => proto::AttributeDataType::F64,
            AttributeDataType::U8Vec3 => proto::AttributeDataType::U8Vec3,
            AttributeDataType::F64Vec3 => proto::AttributeDataType::F64Vec3,
        }
    }
}

impl AttributeData {
    pub fn len(&self) -> usize {
        match self {
            AttributeData::U8(data) => data.len(),
            AttributeData::I64(data) => data.len(),
            AttributeData::U64(data) => data.len(),
            AttributeData::F32(data) => data.len(),
            AttributeData::F64(data) => data.len(),
            AttributeData::U8Vec3(data) => data.len(),
            AttributeData::F64Vec3(data) => data.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn dim(&self) -> usize {
        match self {
            AttributeData::U8(_)
            | AttributeData::I64(_)
            | AttributeData::U64(_)
            | AttributeData::F32(_)
            | AttributeData::F64(_) => 1,
            AttributeData::U8Vec3(_) | AttributeData::F64Vec3(_) => 3,
        }
    }

    pub fn data_type(&self) -> AttributeDataType {
        match self {
            AttributeData::U8(_) => AttributeDataType::U8,
            AttributeData::I64(_) => AttributeDataType::I64,
            AttributeData::U64(_) => AttributeDataType::U64,
            AttributeData::F32(_) => AttributeDataType::F32,
            AttributeData::F64(_) => AttributeDataType::F64,
            AttributeData::U8Vec3(_) => AttributeDataType::U8Vec3,
            AttributeData::F64Vec3(_) => AttributeDataType::F64Vec3,
        }
    }
}

/// General structure that contains points and attached feature attributes.
#[derive(Debug, Clone)]
pub struct PointsBatch {
    pub position: Vec<Vector3<f64>>,
    // BTreeMap for deterministic iteration order.
    pub attributes: BTreeMap<String, AttributeData>,
}

pub use point_viewer_proto_rust::proto;

/// size for batch
pub const NUM_POINTS_PER_BATCH: usize = 500_000;
<commit_msg>Add method to return size of AttributeType (#336)<commit_after>// Copyright 2016 Google Inc.
//
// 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.

pub mod batch_iterator;
pub mod color;
pub mod data_provider;
pub mod errors;
pub mod math;
pub mod octree;
pub mod read_write;
pub mod s2_cells;

use cgmath::Vector3;
use std::collections::BTreeMap;

// Version 9 -> 10: Change in NodeId proto from level (u8) and index (u64) to high (u64) and low
// (u64). We are able to convert the proto on read, so the tools can still read version 9.
// Version 10 -> 11: Change in AxisAlignedCuboid proto from Vector3f min/max to Vector3d min/max.
// We are able to convert the proto on read, so the tools can still read version 9/10.
// Version 11 -> 12: Change in Meta names and structures, to allow both s2 and octree meta.
// We are able to convert the proto on read, so the tools can still read version 9/10/11.
pub const CURRENT_VERSION: i32 = 12;

#[derive(Debug, Clone)]
pub struct Point {
    pub position: cgmath::Vector3<f64>,
    // TODO(sirver): Make color optional, we might not always have it.
    pub color: color::Color<u8>,

    // The intensity of the point if it exists. This value is usually handed through directly by a
    // sensor and has therefore no defined range - or even meaning.
    pub intensity: Option<f32>,
}

pub fn attribute_extension(attribute: &str) -> &str {
    match attribute {
        "position" => "xyz",
        "color" => "rgb",
        _ => attribute,
    }
}

/// General field to describe point feature attributes such as color, intensity, ...
#[derive(Debug, Clone)]
pub enum AttributeData {
    U8(Vec<u8>),
    I64(Vec<i64>),
    U64(Vec<u64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    U8Vec3(Vec<Vector3<u8>>),
    F64Vec3(Vec<Vector3<f64>>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttributeDataType {
    U8,
    I64,
    U64,
    F32,
    F64,
    U8Vec3,
    F64Vec3,
}

impl AttributeDataType {
    pub fn to_proto(&self) -> proto::AttributeDataType {
        match self {
            AttributeDataType::U8 => proto::AttributeDataType::U8,
            AttributeDataType::I64 => proto::AttributeDataType::I64,
            AttributeDataType::U64 => proto::AttributeDataType::U64,
            AttributeDataType::F32 => proto::AttributeDataType::F32,
            AttributeDataType::F64 => proto::AttributeDataType::F64,
            AttributeDataType::U8Vec3 => proto::AttributeDataType::U8Vec3,
            AttributeDataType::F64Vec3 => proto::AttributeDataType::F64Vec3,
        }
    }

    pub fn size_of(&self) -> usize {
        match self {
            AttributeDataType::U8 => 1,
            AttributeDataType::F32 => 4,
            AttributeDataType::I64 | AttributeDataType::U64 | AttributeDataType::F64 => 8,
            AttributeDataType::U8Vec3 => 3,
            AttributeDataType::F64Vec3 => 3 * 8,
        }
    }
}

impl AttributeData {
    pub fn len(&self) -> usize {
        match self {
            AttributeData::U8(data) => data.len(),
            AttributeData::I64(data) => data.len(),
            AttributeData::U64(data) => data.len(),
            AttributeData::F32(data) => data.len(),
            AttributeData::F64(data) => data.len(),
            AttributeData::U8Vec3(data) => data.len(),
            AttributeData::F64Vec3(data) => data.len(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn dim(&self) -> usize {
        match self {
            AttributeData::U8(_)
            | AttributeData::I64(_)
            | AttributeData::U64(_)
            | AttributeData::F32(_)
            | AttributeData::F64(_) => 1,
            AttributeData::U8Vec3(_) | AttributeData::F64Vec3(_) => 3,
        }
    }

    pub fn data_type(&self) -> AttributeDataType {
        match self {
            AttributeData::U8(_) => AttributeDataType::U8,
            AttributeData::I64(_) => AttributeDataType::I64,
            AttributeData::U64(_) => AttributeDataType::U64,
            AttributeData::F32(_) => AttributeDataType::F32,
            AttributeData::F64(_) => AttributeDataType::F64,
            AttributeData::U8Vec3(_) => AttributeDataType::U8Vec3,
            AttributeData::F64Vec3(_) => AttributeDataType::F64Vec3,
        }
    }
}

/// General structure that contains points and attached feature attributes.
#[derive(Debug, Clone)]
pub struct PointsBatch {
    pub position: Vec<Vector3<f64>>,
    // BTreeMap for deterministic iteration order.
    pub attributes: BTreeMap<String, AttributeData>,
}

pub use point_viewer_proto_rust::proto;

/// size for batch
pub const NUM_POINTS_PER_BATCH: usize = 500_000;
<|endoftext|>


<commit_before>//! A library for controlling i3-wm through its ipc interface.

extern crate unix_socket;
extern crate byteorder;
extern crate serde;

use std::process;
use unix_socket::UnixStream;
use std::io;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use serde::json;

mod readhelp;
pub mod reply;

pub enum Event {
    // none of these are complete
    Workspace,
    Output,
    Mode,
    Window,
    BarConfigUpdate,
    Binding
}

/// An error while instantiating an I3Connection. Creating an I3Connection involves first getting
/// the i3 socket path, then connecting to the socket. Either part could go wrong, which is why
/// there are two possibilities here.
#[derive(Debug)]
pub enum I3ConnectError {
    /// An error while getting the socket path
    GetSocketPathError(io::Error),
    /// An error while accessing the socket
    SocketError(io::Error)
}

pub struct I3Connection {
    stream: UnixStream
}

impl I3Connection {

    /// Establishes an IPC connection to i3.
    pub fn connect() -> Result<I3Connection, I3ConnectError> {
        fn get_socket_path() -> io::Result<String> {
            let output = try!(process::Command::new("i3")
                                               .arg("--get-socketpath")
                                               .output());
            if output.status.success() {
                Ok(String::from_utf8_lossy(&output.stdout)
                          .trim_right_matches('\n')
                          .to_owned())
            } else {
                let prefix = "i3 --getsocketpath didn't return 0";
                let error_text = if output.stderr.len() > 0 {
                    format!("{}. stderr: {:?}", prefix, output.stderr)
                } else {
                    prefix.to_owned()
                };
                let error = io::Error::new(io::ErrorKind::Other, error_text);
                Err(error)
            }
        }

        return match get_socket_path() {
            Ok(path) => {
                match UnixStream::connect(path) {
                    Ok(stream) => Ok(I3Connection { stream: stream }),
                    Err(error) => Err(I3ConnectError::SocketError(error))
                }
            }
            Err(error) => Err(I3ConnectError::GetSocketPathError(error))
        }
    }

    fn send_message(&mut self, message_type: u32, payload: &str) -> io::Result<()> {
        let mut bytes = Vec::with_capacity(14 + payload.len());
        bytes.extend("i3-ipc".bytes());                              // 6 bytes
        try!(bytes.write_u32::<LittleEndian>(payload.len() as u32)); // 4 bytes
        try!(bytes.write_u32::<LittleEndian>(message_type));         // 4 bytes
        bytes.extend(payload.bytes());                               // payload.len() bytes
        self.stream.write_all(&bytes[..])
    }

    fn receive_message(&mut self) -> io::Result<String> {
        let magic_data = try!(readhelp::read_exact(&mut self.stream, 6));
        let magic_string = String::from_utf8_lossy(&magic_data);
        if magic_string != "i3-ipc" {
            let error_text = format!("unexpected magic string: expected 'i3-ipc' but got {}",
                                      magic_string);
            return Err(io::Error::new(io::ErrorKind::Other, error_text));
        }
        let payload_len = try!(self.stream.read_u32::<LittleEndian>());
        let message_type = try!(self.stream.read_u32::<LittleEndian>());
        let payload_data = try!(readhelp::read_exact(&mut self.stream, payload_len as usize));
        Ok(String::from_utf8_lossy(&payload_data).into_owned())
    }

    /// The payload of the message is a command for i3 (like the commands you can bind to keys
    /// in the configuration file) and will be executed directly after receiving it.
    pub fn command(&mut self, string: &str) -> io::Result<reply::Command> {
        try!(self.send_message(0, string));
        let payload = try!(self.receive_message());

        // assumes valid json
        let j: json::Value = json::from_str(&payload).unwrap();
        let commands = j.as_array().unwrap();
        let vec: Vec<_>
            = commands.iter()
                      .map(|c|
                           reply::CommandOutcome {
                               success: c.find("success").unwrap().as_boolean().unwrap(),
                               error: match c.find("error") {
                                   Some(val) => Some(val.as_string().unwrap().to_owned()),
                                   None => None
                               }
                           })
                      .collect();

        Ok(reply::Command { outcomes: vec })
    }

    /// Gets the current workspaces.
    pub fn get_workspaces(&mut self) -> io::Result<reply::Workspaces> {
        panic!("not implemented");
    }

    /// Subscribes your connection to certain events.
    pub fn subscribe(&mut self) -> Result<reply::Subscribe, String> {
        panic!("not implemented");
    }

    /// Gets the current outputs.
    pub fn get_outputs(&mut self) -> Result<reply::Outputs, String> {
        panic!("not implemented");
    }

    /// Gets the layout tree. i3 uses a tree as data structure which includes every container.
    pub fn get_tree(&mut self) -> Result<reply::Tree, String> {
        panic!("not implemented");
    }

    /// Gets a list of marks (identifiers for containers to easily jump to them later).
    pub fn get_marks(&mut self) -> Result<reply::Marks, String> {
        panic!("not implemented");
    }

    /// Gets an array with all configured bar IDs.
    pub fn get_bar_ids(&mut self) -> Result<reply::BarIds, String> {
        panic!("not implemented");
    }

    /// Gets the configuration of the workspace bar with the given ID.
    pub fn get_bar_config(&mut self, id: &str) -> Result<reply::BarConfig, String> {
        panic!("not implemented");
    }

    /// Gets the version of i3. The reply will include the major, minor, patch and human-readable
    /// version.
    pub fn get_version(&mut self) -> Result<reply::Version, String> {
        panic!("not implemented");
    }
}

#[cfg(test)]
mod test {
    use I3Connection;

    // for the following tests send a request and get the reponse.
    // response types are specific so often getting them at all indicates success.
    // can't do much better without mocking an i3 installation.

    #[test]
    fn connect() {
        I3Connection::connect().unwrap();
    }

    #[test]
    fn command_nothing() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("").unwrap();
        assert_eq!(result.outcomes.len(), 0);
    }

    #[test]
    fn command_single_sucess() {
        let mut connection = I3Connection::connect().unwrap();
        let a = connection.command("exec /bin/true").unwrap();
        assert_eq!(a.outcomes.len(), 1);
        assert!(a.outcomes[0].success);
    }

    #[test]
    fn command_multiple_success() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("exec /bin/true; exec /bin/true").unwrap();
        assert_eq!(result.outcomes.len(), 2);
        assert!(result.outcomes[0].success);
        assert!(result.outcomes[1].success);
    }

    #[test]
    fn command_fail() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("ThisIsClearlyNotACommand").unwrap();
        assert_eq!(result.outcomes.len(), 1);
        assert!(!result.outcomes[0].success);
    }

    #[test]
    fn get_workspaces() {
        I3Connection::connect().unwrap().get_workspaces().unwrap();
    }

    #[test]
    fn subscribe() {
        I3Connection::connect().unwrap().subscribe().unwrap();
    }

    #[test]
    fn get_outputs() {
        I3Connection::connect().unwrap().get_outputs().unwrap();
    }

    #[test]
    fn get_tree() {
        I3Connection::connect().unwrap().get_tree().unwrap();
    }

    #[test]
    fn get_marks() {
        I3Connection::connect().unwrap().get_marks().unwrap();
    }

    #[test]
    fn get_bar_ids() {
        I3Connection::connect().unwrap().get_bar_ids().unwrap();
    }

    #[test]
    fn get_bar_ids_and_one_config() {
        let mut connection = I3Connection::connect().unwrap();
        let ids = connection.get_bar_ids().unwrap().ids;
        let oneconfig = connection.get_bar_config(&ids[0]).unwrap();
    }

    #[test]
    fn get_version() {
        I3Connection::connect().unwrap().get_version().unwrap();
    }
}
<commit_msg>Change request return type to io::Result<commit_after>//! A library for controlling i3-wm through its ipc interface.

extern crate unix_socket;
extern crate byteorder;
extern crate serde;

use std::process;
use unix_socket::UnixStream;
use std::io;
use std::io::prelude::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use serde::json;

mod readhelp;
pub mod reply;

pub enum Event {
    // none of these are complete
    Workspace,
    Output,
    Mode,
    Window,
    BarConfigUpdate,
    Binding
}

/// An error while instantiating an I3Connection. Creating an I3Connection involves first getting
/// the i3 socket path, then connecting to the socket. Either part could go wrong, which is why
/// there are two possibilities here.
#[derive(Debug)]
pub enum I3ConnectError {
    /// An error while getting the socket path
    GetSocketPathError(io::Error),
    /// An error while accessing the socket
    SocketError(io::Error)
}

pub struct I3Connection {
    stream: UnixStream
}

impl I3Connection {

    /// Establishes an IPC connection to i3.
    pub fn connect() -> Result<I3Connection, I3ConnectError> {
        fn get_socket_path() -> io::Result<String> {
            let output = try!(process::Command::new("i3")
                                               .arg("--get-socketpath")
                                               .output());
            if output.status.success() {
                Ok(String::from_utf8_lossy(&output.stdout)
                          .trim_right_matches('\n')
                          .to_owned())
            } else {
                let prefix = "i3 --getsocketpath didn't return 0";
                let error_text = if output.stderr.len() > 0 {
                    format!("{}. stderr: {:?}", prefix, output.stderr)
                } else {
                    prefix.to_owned()
                };
                let error = io::Error::new(io::ErrorKind::Other, error_text);
                Err(error)
            }
        }

        return match get_socket_path() {
            Ok(path) => {
                match UnixStream::connect(path) {
                    Ok(stream) => Ok(I3Connection { stream: stream }),
                    Err(error) => Err(I3ConnectError::SocketError(error))
                }
            }
            Err(error) => Err(I3ConnectError::GetSocketPathError(error))
        }
    }

    fn send_message(&mut self, message_type: u32, payload: &str) -> io::Result<()> {
        let mut bytes = Vec::with_capacity(14 + payload.len());
        bytes.extend("i3-ipc".bytes());                              // 6 bytes
        try!(bytes.write_u32::<LittleEndian>(payload.len() as u32)); // 4 bytes
        try!(bytes.write_u32::<LittleEndian>(message_type));         // 4 bytes
        bytes.extend(payload.bytes());                               // payload.len() bytes
        self.stream.write_all(&bytes[..])
    }

    fn receive_message(&mut self) -> io::Result<String> {
        let magic_data = try!(readhelp::read_exact(&mut self.stream, 6));
        let magic_string = String::from_utf8_lossy(&magic_data);
        if magic_string != "i3-ipc" {
            let error_text = format!("unexpected magic string: expected 'i3-ipc' but got {}",
                                      magic_string);
            return Err(io::Error::new(io::ErrorKind::Other, error_text));
        }
        let payload_len = try!(self.stream.read_u32::<LittleEndian>());
        let message_type = try!(self.stream.read_u32::<LittleEndian>());
        let payload_data = try!(readhelp::read_exact(&mut self.stream, payload_len as usize));
        Ok(String::from_utf8_lossy(&payload_data).into_owned())
    }

    /// The payload of the message is a command for i3 (like the commands you can bind to keys
    /// in the configuration file) and will be executed directly after receiving it.
    pub fn command(&mut self, string: &str) -> io::Result<reply::Command> {
        try!(self.send_message(0, string));
        let payload = try!(self.receive_message());

        // assumes valid json
        let j: json::Value = json::from_str(&payload).unwrap();
        let commands = j.as_array().unwrap();
        let vec: Vec<_>
            = commands.iter()
                      .map(|c|
                           reply::CommandOutcome {
                               success: c.find("success").unwrap().as_boolean().unwrap(),
                               error: match c.find("error") {
                                   Some(val) => Some(val.as_string().unwrap().to_owned()),
                                   None => None
                               }
                           })
                      .collect();

        Ok(reply::Command { outcomes: vec })
    }

    /// Gets the current workspaces.
    pub fn get_workspaces(&mut self) -> io::Result<reply::Workspaces> {
        panic!("not implemented");
    }

    /// Subscribes your connection to certain events.
    pub fn subscribe(&mut self) -> io::Result<reply::Subscribe> {
        panic!("not implemented");
    }

    /// Gets the current outputs.
    pub fn get_outputs(&mut self) -> io::Result<reply::Outputs> {
        panic!("not implemented");
    }

    /// Gets the layout tree. i3 uses a tree as data structure which includes every container.
    pub fn get_tree(&mut self) -> io::Result<reply::Tree> {
        panic!("not implemented");
    }

    /// Gets a list of marks (identifiers for containers to easily jump to them later).
    pub fn get_marks(&mut self) -> io::Result<reply::Marks> {
        panic!("not implemented");
    }

    /// Gets an array with all configured bar IDs.
    pub fn get_bar_ids(&mut self) -> io::Result<reply::BarIds> {
        panic!("not implemented");
    }

    /// Gets the configuration of the workspace bar with the given ID.
    pub fn get_bar_config(&mut self, id: &str) -> io::Result<reply::BarConfig> {
        panic!("not implemented");
    }

    /// Gets the version of i3. The reply will include the major, minor, patch and human-readable
    /// version.
    pub fn get_version(&mut self) -> io::Result<reply::Version> {
        panic!("not implemented");
    }
}

#[cfg(test)]
mod test {
    use I3Connection;

    // for the following tests send a request and get the reponse.
    // response types are specific so often getting them at all indicates success.
    // can't do much better without mocking an i3 installation.

    #[test]
    fn connect() {
        I3Connection::connect().unwrap();
    }

    #[test]
    fn command_nothing() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("").unwrap();
        assert_eq!(result.outcomes.len(), 0);
    }

    #[test]
    fn command_single_sucess() {
        let mut connection = I3Connection::connect().unwrap();
        let a = connection.command("exec /bin/true").unwrap();
        assert_eq!(a.outcomes.len(), 1);
        assert!(a.outcomes[0].success);
    }

    #[test]
    fn command_multiple_success() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("exec /bin/true; exec /bin/true").unwrap();
        assert_eq!(result.outcomes.len(), 2);
        assert!(result.outcomes[0].success);
        assert!(result.outcomes[1].success);
    }

    #[test]
    fn command_fail() {
        let mut connection = I3Connection::connect().unwrap();
        let result = connection.command("ThisIsClearlyNotACommand").unwrap();
        assert_eq!(result.outcomes.len(), 1);
        assert!(!result.outcomes[0].success);
    }

    #[test]
    fn get_workspaces() {
        I3Connection::connect().unwrap().get_workspaces().unwrap();
    }

    #[test]
    fn subscribe() {
        I3Connection::connect().unwrap().subscribe().unwrap();
    }

    #[test]
    fn get_outputs() {
        I3Connection::connect().unwrap().get_outputs().unwrap();
    }

    #[test]
    fn get_tree() {
        I3Connection::connect().unwrap().get_tree().unwrap();
    }

    #[test]
    fn get_marks() {
        I3Connection::connect().unwrap().get_marks().unwrap();
    }

    #[test]
    fn get_bar_ids() {
        I3Connection::connect().unwrap().get_bar_ids().unwrap();
    }

    #[test]
    fn get_bar_ids_and_one_config() {
        let mut connection = I3Connection::connect().unwrap();
        let ids = connection.get_bar_ids().unwrap().ids;
        let oneconfig = connection.get_bar_config(&ids[0]).unwrap();
    }

    #[test]
    fn get_version() {
        I3Connection::connect().unwrap().get_version().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate libc;
#[cfg(feature = "v5-20")]
use libc::c_void;
use libc::{c_char, c_int, size_t};

// `libmagic` API as in "magic.h"

#[allow(non_camel_case_types)]
// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
#[repr(C)]
pub struct magic_set {
    _data: [u8; 0],
    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

#[allow(non_camel_case_types)]
pub type magic_t = *mut magic_set;

pub const MAGIC_NONE: c_int = 0x000_0000;
pub const MAGIC_DEBUG: c_int = 0x000_0001;
pub const MAGIC_SYMLINK: c_int = 0x000_0002;
pub const MAGIC_COMPRESS: c_int = 0x000_0004;
pub const MAGIC_DEVICES: c_int = 0x000_0008;
pub const MAGIC_MIME_TYPE: c_int = 0x000_0010;
pub const MAGIC_CONTINUE: c_int = 0x000_0020;
pub const MAGIC_CHECK: c_int = 0x000_0040;
pub const MAGIC_PRESERVE_ATIME: c_int = 0x000_0080;
pub const MAGIC_RAW: c_int = 0x000_0100;
pub const MAGIC_ERROR: c_int = 0x000_0200;
pub const MAGIC_MIME_ENCODING: c_int = 0x000_0400;
pub const MAGIC_MIME: c_int = MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING;
pub const MAGIC_APPLE: c_int = 0x00_0800;
#[cfg(feature = "v5-23")]
pub const MAGIC_EXTENSION: c_int = 0x100_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_COMPRESS_TRANSP: c_int = 0x200_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_NODESC: c_int = MAGIC_EXTENSION | MAGIC_MIME | MAGIC_APPLE;

pub const MAGIC_NO_CHECK_COMPRESS: c_int = 0x000_1000;
pub const MAGIC_NO_CHECK_TAR: c_int = 0x000_2000;
pub const MAGIC_NO_CHECK_SOFT: c_int = 0x000_4000;
pub const MAGIC_NO_CHECK_APPTYPE: c_int = 0x000_8000;
pub const MAGIC_NO_CHECK_ELF: c_int = 0x001_0000;
pub const MAGIC_NO_CHECK_TEXT: c_int = 0x002_0000;
pub const MAGIC_NO_CHECK_CDF: c_int = 0x004_0000;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_CSV: c_int = 0x008_0000;
pub const MAGIC_NO_CHECK_TOKENS: c_int = 0x010_0000;
pub const MAGIC_NO_CHECK_ENCODING: c_int = 0x020_0000;
#[cfg(feature = "v5-35")]
pub const MAGIC_NO_CHECK_JSON: c_int = 0x040_0000;

#[cfg(all(feature = "v5-05", not(feature = "v5-10")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = 0x3f_b000;
#[cfg(all(feature = "v5-10", not(feature = "v5-35")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING;
#[cfg(all(feature = "v5-35", not(feature = "v5-38")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CSV      |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;

#[deprecated]
pub const MAGIC_NO_CHECK_ASCII: c_int = MAGIC_NO_CHECK_TEXT;

#[deprecated]
pub const MAGIC_NO_CHECK_FORTRAN: c_int = 0x00_0000;
#[deprecated]
pub const MAGIC_NO_CHECK_TROFF: c_int = 0x00_0000;

// TODO: MAGIC_VERSION string

// TODO: MAGIC_SNPRINTB bytes

#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_INDIR_MAX: c_int = 0;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_NAME_MAX: c_int = 1;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_PHNUM_MAX: c_int = 2;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_SHNUM_MAX: c_int = 3;
#[cfg(feature = "v5-22")]
pub const MAGIC_PARAM_ELF_NOTES_MAX: c_int = 4;
#[cfg(feature = "v5-25")]
pub const MAGIC_PARAM_REGEX_MAX: c_int = 5;
#[cfg(feature = "v5-27")]
pub const MAGIC_PARAM_BYTES_MAX: c_int = 6;
#[cfg(feature = "v5-40")]
pub const MAGIC_PARAM_ENCODING_MAX: c_int = 7;

// NOTE: the following are from `file.h`, but part of `magic.h` API
#[cfg(feature = "v5-04")]
pub const FILE_LOAD: c_int = 0;
#[cfg(feature = "v5-04")]
pub const FILE_CHECK: c_int = 1;
#[cfg(feature = "v5-04")]
pub const FILE_COMPILE: c_int = 2;
#[cfg(feature = "v5-05")]
pub const FILE_LIST: c_int = 3;

extern "C" {
    pub fn magic_open(flags: c_int) -> magic_t;
    pub fn magic_close(cookie: magic_t);

    #[cfg(feature = "v5-04")]
    pub fn magic_getpath(magicfile: *const c_char, action: c_int) -> *const c_char;
    pub fn magic_file(cookie: magic_t, filename: *const c_char) -> *const c_char;
    pub fn magic_descriptor(cookie: magic_t, fd: c_int) -> *const c_char;
    pub fn magic_buffer(cookie: magic_t, buffer: *const u8, length: size_t) -> *const c_char;

    pub fn magic_error(cookie: magic_t) -> *const c_char;
    #[cfg(feature = "v5-32")]
    pub fn magic_getflags(cookie: magic_t) -> c_int;
    #[must_use]
    pub fn magic_setflags(cookie: magic_t, flags: c_int) -> c_int;

    #[cfg(feature = "v5-13")]
    pub fn magic_version() -> c_int;
    #[must_use]
    pub fn magic_load(cookie: magic_t, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-20")]
    #[must_use]
    pub fn magic_load_buffers(
        cookie: magic_t,
        buffers: *mut *mut c_void,
        sizes: *mut size_t,
        nbuffers: size_t,
    ) -> c_int;

    #[must_use]
    pub fn magic_compile(cookie: magic_t, filename: *const c_char) -> c_int;
    #[must_use]
    pub fn magic_check(cookie: magic_t, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-05")]
    #[must_use]
    pub fn magic_list(cookie: magic_t, filename: *const c_char) -> c_int;
    pub fn magic_errno(cookie: magic_t) -> *const c_int;

    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_setparam(cookie: magic_t, param: c_int, value: *const c_void) -> c_int;
    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_getparam(cookie: magic_t, param: c_int, value: *mut c_void) -> c_int;
}

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

    // Those tests are mostly just sanity checks to see if linkage works,
    // they are NOT testing `libmagic` API/implementation

    #[test]
    fn test_magic_open() {
        unsafe {
            magic_open(MAGIC_NONE);
        }
    }

    #[test]
    fn test_magic_close() {
        unsafe {
            magic_close(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-04")]
    #[test]
    fn test_magic_getpath() {
        unsafe {
            magic_getpath(std::ptr::null(), FILE_CHECK);
        }
    }

    #[test]
    fn test_magic_file() {
        unsafe {
            magic_file(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_descriptor() {
        unsafe {
            magic_descriptor(std::ptr::null_mut(), -1);
        }
    }

    #[test]
    fn test_magic_buffer() {
        unsafe {
            magic_buffer(std::ptr::null_mut(), std::ptr::null(), 0);
        }
    }

    #[test]
    fn test_magic_error() {
        unsafe {
            magic_error(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-32")]
    #[test]
    fn test_magic_getflags() {
        unsafe {
            magic_getflags(std::ptr::null_mut());
        }
    }

    #[test]
    fn test_magic_setflags() {
        unsafe {
            let _ = magic_setflags(std::ptr::null_mut(), MAGIC_NONE);
        }
    }

    #[cfg(feature = "v5-13")]
    #[test]
    fn test_magic_version() {
        unsafe {
            magic_version();
        }
    }

    #[test]
    fn test_magic_load() {
        unsafe {
            let _ = magic_load(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-20")]
    #[test]
    fn test_magic_load_buffers() {
        unsafe {
            let _ = magic_load_buffers(
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                0,
            );
        }
    }

    #[test]
    fn test_magic_compile() {
        unsafe {
            let _ = magic_compile(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_check() {
        unsafe {
            let _ = magic_check(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-05")]
    #[test]
    fn test_magic_list() {
        unsafe {
            let _ = magic_list(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_errno() {
        unsafe {
            magic_errno(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_setparam() {
        unsafe {
            let _ = magic_setparam(
                std::ptr::null_mut(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null(),
            );
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_getparam() {
        unsafe {
            let _ = magic_getparam(
                std::ptr::null_mut(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null_mut(),
            );
        }
    }
}
<commit_msg>Fix return type of `magic_errno`<commit_after>extern crate libc;
#[cfg(feature = "v5-20")]
use libc::c_void;
use libc::{c_char, c_int, size_t};

// `libmagic` API as in "magic.h"

#[allow(non_camel_case_types)]
// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
#[repr(C)]
pub struct magic_set {
    _data: [u8; 0],
    _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

#[allow(non_camel_case_types)]
pub type magic_t = *mut magic_set;

pub const MAGIC_NONE: c_int = 0x000_0000;
pub const MAGIC_DEBUG: c_int = 0x000_0001;
pub const MAGIC_SYMLINK: c_int = 0x000_0002;
pub const MAGIC_COMPRESS: c_int = 0x000_0004;
pub const MAGIC_DEVICES: c_int = 0x000_0008;
pub const MAGIC_MIME_TYPE: c_int = 0x000_0010;
pub const MAGIC_CONTINUE: c_int = 0x000_0020;
pub const MAGIC_CHECK: c_int = 0x000_0040;
pub const MAGIC_PRESERVE_ATIME: c_int = 0x000_0080;
pub const MAGIC_RAW: c_int = 0x000_0100;
pub const MAGIC_ERROR: c_int = 0x000_0200;
pub const MAGIC_MIME_ENCODING: c_int = 0x000_0400;
pub const MAGIC_MIME: c_int = MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING;
pub const MAGIC_APPLE: c_int = 0x00_0800;
#[cfg(feature = "v5-23")]
pub const MAGIC_EXTENSION: c_int = 0x100_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_COMPRESS_TRANSP: c_int = 0x200_0000;
#[cfg(feature = "v5-23")]
pub const MAGIC_NODESC: c_int = MAGIC_EXTENSION | MAGIC_MIME | MAGIC_APPLE;

pub const MAGIC_NO_CHECK_COMPRESS: c_int = 0x000_1000;
pub const MAGIC_NO_CHECK_TAR: c_int = 0x000_2000;
pub const MAGIC_NO_CHECK_SOFT: c_int = 0x000_4000;
pub const MAGIC_NO_CHECK_APPTYPE: c_int = 0x000_8000;
pub const MAGIC_NO_CHECK_ELF: c_int = 0x001_0000;
pub const MAGIC_NO_CHECK_TEXT: c_int = 0x002_0000;
pub const MAGIC_NO_CHECK_CDF: c_int = 0x004_0000;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_CSV: c_int = 0x008_0000;
pub const MAGIC_NO_CHECK_TOKENS: c_int = 0x010_0000;
pub const MAGIC_NO_CHECK_ENCODING: c_int = 0x020_0000;
#[cfg(feature = "v5-35")]
pub const MAGIC_NO_CHECK_JSON: c_int = 0x040_0000;

#[cfg(all(feature = "v5-05", not(feature = "v5-10")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = 0x3f_b000;
#[cfg(all(feature = "v5-10", not(feature = "v5-35")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING;
#[cfg(all(feature = "v5-35", not(feature = "v5-38")))]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;
#[cfg(feature = "v5-38")]
pub const MAGIC_NO_CHECK_BUILTIN: c_int = MAGIC_NO_CHECK_COMPRESS |
MAGIC_NO_CHECK_TAR      |
// MAGIC_NO_CHECK_SOFT  |
MAGIC_NO_CHECK_APPTYPE  |
MAGIC_NO_CHECK_ELF      |
MAGIC_NO_CHECK_TEXT     |
MAGIC_NO_CHECK_CSV      |
MAGIC_NO_CHECK_CDF      |
MAGIC_NO_CHECK_TOKENS   |
MAGIC_NO_CHECK_ENCODING |
MAGIC_NO_CHECK_JSON;

#[deprecated]
pub const MAGIC_NO_CHECK_ASCII: c_int = MAGIC_NO_CHECK_TEXT;

#[deprecated]
pub const MAGIC_NO_CHECK_FORTRAN: c_int = 0x00_0000;
#[deprecated]
pub const MAGIC_NO_CHECK_TROFF: c_int = 0x00_0000;

// TODO: MAGIC_VERSION string

// TODO: MAGIC_SNPRINTB bytes

#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_INDIR_MAX: c_int = 0;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_NAME_MAX: c_int = 1;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_PHNUM_MAX: c_int = 2;
#[cfg(feature = "v5-21")]
pub const MAGIC_PARAM_ELF_SHNUM_MAX: c_int = 3;
#[cfg(feature = "v5-22")]
pub const MAGIC_PARAM_ELF_NOTES_MAX: c_int = 4;
#[cfg(feature = "v5-25")]
pub const MAGIC_PARAM_REGEX_MAX: c_int = 5;
#[cfg(feature = "v5-27")]
pub const MAGIC_PARAM_BYTES_MAX: c_int = 6;
#[cfg(feature = "v5-40")]
pub const MAGIC_PARAM_ENCODING_MAX: c_int = 7;

// NOTE: the following are from `file.h`, but part of `magic.h` API
#[cfg(feature = "v5-04")]
pub const FILE_LOAD: c_int = 0;
#[cfg(feature = "v5-04")]
pub const FILE_CHECK: c_int = 1;
#[cfg(feature = "v5-04")]
pub const FILE_COMPILE: c_int = 2;
#[cfg(feature = "v5-05")]
pub const FILE_LIST: c_int = 3;

extern "C" {
    pub fn magic_open(flags: c_int) -> magic_t;
    pub fn magic_close(cookie: magic_t);

    #[cfg(feature = "v5-04")]
    pub fn magic_getpath(magicfile: *const c_char, action: c_int) -> *const c_char;
    pub fn magic_file(cookie: magic_t, filename: *const c_char) -> *const c_char;
    pub fn magic_descriptor(cookie: magic_t, fd: c_int) -> *const c_char;
    pub fn magic_buffer(cookie: magic_t, buffer: *const u8, length: size_t) -> *const c_char;

    pub fn magic_error(cookie: magic_t) -> *const c_char;
    #[cfg(feature = "v5-32")]
    pub fn magic_getflags(cookie: magic_t) -> c_int;
    #[must_use]
    pub fn magic_setflags(cookie: magic_t, flags: c_int) -> c_int;

    #[cfg(feature = "v5-13")]
    pub fn magic_version() -> c_int;
    #[must_use]
    pub fn magic_load(cookie: magic_t, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-20")]
    #[must_use]
    pub fn magic_load_buffers(
        cookie: magic_t,
        buffers: *mut *mut c_void,
        sizes: *mut size_t,
        nbuffers: size_t,
    ) -> c_int;

    #[must_use]
    pub fn magic_compile(cookie: magic_t, filename: *const c_char) -> c_int;
    #[must_use]
    pub fn magic_check(cookie: magic_t, filename: *const c_char) -> c_int;
    #[cfg(feature = "v5-05")]
    #[must_use]
    pub fn magic_list(cookie: magic_t, filename: *const c_char) -> c_int;
    pub fn magic_errno(cookie: magic_t) -> c_int;

    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_setparam(cookie: magic_t, param: c_int, value: *const c_void) -> c_int;
    #[cfg(feature = "v5-21")]
    #[must_use]
    pub fn magic_getparam(cookie: magic_t, param: c_int, value: *mut c_void) -> c_int;
}

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

    // Those tests are mostly just sanity checks to see if linkage works,
    // they are NOT testing `libmagic` API/implementation

    #[test]
    fn test_magic_open() {
        unsafe {
            magic_open(MAGIC_NONE);
        }
    }

    #[test]
    fn test_magic_close() {
        unsafe {
            magic_close(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-04")]
    #[test]
    fn test_magic_getpath() {
        unsafe {
            magic_getpath(std::ptr::null(), FILE_CHECK);
        }
    }

    #[test]
    fn test_magic_file() {
        unsafe {
            magic_file(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_descriptor() {
        unsafe {
            magic_descriptor(std::ptr::null_mut(), -1);
        }
    }

    #[test]
    fn test_magic_buffer() {
        unsafe {
            magic_buffer(std::ptr::null_mut(), std::ptr::null(), 0);
        }
    }

    #[test]
    fn test_magic_error() {
        unsafe {
            magic_error(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-32")]
    #[test]
    fn test_magic_getflags() {
        unsafe {
            magic_getflags(std::ptr::null_mut());
        }
    }

    #[test]
    fn test_magic_setflags() {
        unsafe {
            let _ = magic_setflags(std::ptr::null_mut(), MAGIC_NONE);
        }
    }

    #[cfg(feature = "v5-13")]
    #[test]
    fn test_magic_version() {
        unsafe {
            magic_version();
        }
    }

    #[test]
    fn test_magic_load() {
        unsafe {
            let _ = magic_load(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-20")]
    #[test]
    fn test_magic_load_buffers() {
        unsafe {
            let _ = magic_load_buffers(
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                std::ptr::null_mut(),
                0,
            );
        }
    }

    #[test]
    fn test_magic_compile() {
        unsafe {
            let _ = magic_compile(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_check() {
        unsafe {
            let _ = magic_check(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[cfg(feature = "v5-05")]
    #[test]
    fn test_magic_list() {
        unsafe {
            let _ = magic_list(std::ptr::null_mut(), std::ptr::null());
        }
    }

    #[test]
    fn test_magic_errno() {
        unsafe {
            magic_errno(std::ptr::null_mut());
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_setparam() {
        unsafe {
            let _ = magic_setparam(
                std::ptr::null_mut(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null(),
            );
        }
    }

    #[cfg(feature = "v5-21")]
    #[test]
    fn test_magic_getparam() {
        unsafe {
            let _ = magic_getparam(
                std::ptr::null_mut(),
                MAGIC_PARAM_INDIR_MAX,
                std::ptr::null_mut(),
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{VecDeque, HashSet};

pub fn puzzle(input: &str) -> u32 {
    let start_point = Point { x: 1, y: 1};
    let end_point = Point { x: 31, y: 39 };
    let mut queue = VecDeque::new();
    let mut seen = HashSet::new();

    queue.push_back((start_point, 0));
    seen.insert(start_point);

    while let Some((point, distance)) = queue.pop_front() {
        for &neighbor in point.neighbors().iter().filter(|p| is_empty(p)) {
            if neighbor == end_point {
                return distance + 1;
            }
            if !seen.contains(&neighbor) {
                queue.push_back((neighbor, distance + 1));
                seen.insert(neighbor);
            }
        }
    }
    panic!("never got to the end!");
}

#[derive(PartialEq, Eq, Hash, Copy, Clone)]
struct Point {
    x: u32,
    y: u32,
}

impl Point {
    fn neighbors(&self) -> Vec<Point> {
        let changed_xs = [self.x.checked_sub(1), self.x.checked_add(1)];
        let changed_xs = changed_xs.iter()
            .flat_map(|x| x)
            .map(|&x| Point { x: x, y: self.y });
        let changed_ys = [self.y.checked_sub(1), self.y.checked_add(1)];
        let changed_ys = changed_ys.iter()
            .flat_map(|y| y)
            .map(|&y| Point { x: self.x, y: y });

        changed_xs.chain(changed_ys).collect()
    }
}

fn is_empty(point: &Point) -> bool {
    let &Point { x, y } = point;
    (x*x + 3*x + 2*x*y + y + y*y + 1358).count_ones() % 2 == 0
}

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

}
<commit_msg>Hacktastic but it works, if you only look at the first print<commit_after>use std::collections::{VecDeque, HashSet};

pub fn puzzle(input: &str) -> u32 {
    let start_point = Point { x: 1, y: 1};
    let end_point = Point { x: 31, y: 39 };
    let mut queue = VecDeque::new();
    let mut seen = HashSet::new();

    queue.push_back((start_point, 0));
    seen.insert(start_point);

    while let Some((point, distance)) = queue.pop_front() {
        if distance > 50 {
            println!("{} unique locations seen", seen.len() - queue.len() - 1);
        }
        for &neighbor in point.neighbors().iter().filter(|p| is_empty(p)) {
            if neighbor == end_point {
                return distance + 1;
            }
            if !seen.contains(&neighbor) {
                queue.push_back((neighbor, distance + 1));
                seen.insert(neighbor);
            }
        }
    }
    panic!("never got to the end!");
}

#[derive(PartialEq, Eq, Hash, Copy, Clone)]
struct Point {
    x: u32,
    y: u32,
}

impl Point {
    fn neighbors(&self) -> Vec<Point> {
        let changed_xs = [self.x.checked_sub(1), self.x.checked_add(1)];
        let changed_xs = changed_xs.iter()
            .flat_map(|x| x)
            .map(|&x| Point { x: x, y: self.y });
        let changed_ys = [self.y.checked_sub(1), self.y.checked_add(1)];
        let changed_ys = changed_ys.iter()
            .flat_map(|y| y)
            .map(|&y| Point { x: self.x, y: y });

        changed_xs.chain(changed_ys).collect()
    }
}

fn is_empty(point: &Point) -> bool {
    let &Point { x, y } = point;
    (x*x + 3*x + 2*x*y + y + y*y + 1358).count_ones() % 2 == 0
}

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

}
<|endoftext|>


<commit_before>#![crate_id="civet"]
#![crate_type="rlib"]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult,util};
use std::collections::HashMap;

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: Request<'a>
}

pub struct Request<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>
}

pub struct CopiedRequest {
    pub headers: HashMap<String, String>,
    pub method: Option<String>,
    pub url: Option<String>,
    pub http_version: Option<String>,
    pub query_string: Option<String>,
    pub remote_user: Option<String>,
    pub remote_ip: IpAddr,
    pub remote_port: u16,
    pub is_ssl: bool
}

impl<'a> Request<'a> {
    pub fn copy(&self) -> CopiedRequest {
        let mut headers = HashMap::new();

        for (key, value) in self.headers().iter() {
            headers.insert(key.to_str(), value.to_str());
        }

        CopiedRequest {
            headers: headers,
            method: self.method().map(|a| a.to_str()),
            url: self.url().map(|a| a.to_str()),
            http_version: self.http_version().map(|a| a.to_str()),
            query_string: self.query_string().map(|a| a.to_str()),
            remote_user: self.remote_user().map(|a| a.to_str()),
            remote_ip: self.remote_ip(),
            remote_port: self.remote_port(),
            is_ssl: self.is_ssl()
        }
    }

    pub fn get_header<S: Str>(&mut self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn count_headers(&self) -> uint {
        self.request_info.num_headers() as uint
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        self.request_info.method()
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        self.request_info.url()
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        self.request_info.http_version()
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        self.request_info.remote_user()
    }

    pub fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    pub fn remote_port(&self) -> u16 {
        self.request_info.remote_port() as u16
    }

    pub fn is_ssl(&self) -> bool {
        self.request_info.is_ssl()
    }

    pub fn headers<'a>(&'a self) -> Headers<'a> {
        Headers { conn: self.conn }
    }
}

pub struct Response {
    status: status::StatusCode,
    headers: HashMap<String, String>,
    body: Box<Reader + Send>,
}

impl Response {
    pub fn new<S: ToStatusCode, R: Reader + Send>(
        status: S,
        headers: HashMap<String, String>,
        body: R) -> Response
    {
        Response {
            status: status.to_status().unwrap(),
            headers: headers,
            body: box body,
        }
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = Request { conn: conn, request_info: info };
                Ok(Connection {
                    request: request
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for Request<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> Headers<'a> {
    pub fn find<S: Str>(&self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn iter<'a>(&'a self) -> HeaderIterator<'a> {
        HeaderIterator::new(self.conn)
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, &'a str)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, &'a str)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = headers.get(pos);
            self.position += 1;
            header.name().map(|name| (name, header.value().unwrap()))
        }
    }
}

pub type ServerHandler = fn(&mut Request) -> IoResult<Response>;

pub struct Server(raw::Server<ServerHandler>);

impl Server {
    pub fn start(options: Config, handler: ServerHandler)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            callback: &ServerHandler) -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = (*callback)(&mut connection.request);
            let writer = &mut connection;

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(writer)),
            };
            let (code, string) = status.to_code();
            try!(write!(writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                try!(write!(writer, "{}: {}\r\n", key, value).map_err(|_| ()));
            }

            try!(write!(writer, "\r\n").map_err(|_| ()));
            try!(util::copy(&mut body, writer).map_err(|_| ()));

            Ok(())
        }

        let raw_callback = raw::ServerCallback::new(internal_handler, handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_str())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_str())
    }
}

#[cfg(test)]
mod test {
    use std::io::test::next_test_ip4;
    use super::{Server, Config, Request, Response};
    use std::io::IoResult;

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }
}
<commit_msg>Make handling a request a trait object<commit_after>#![crate_id="civet"]
#![crate_type="rlib"]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult,util};
use std::collections::HashMap;

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: Request<'a>
}

pub struct Request<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>
}

pub struct CopiedRequest {
    pub headers: HashMap<String, String>,
    pub method: Option<String>,
    pub url: Option<String>,
    pub http_version: Option<String>,
    pub query_string: Option<String>,
    pub remote_user: Option<String>,
    pub remote_ip: IpAddr,
    pub remote_port: u16,
    pub is_ssl: bool
}

impl<'a> Request<'a> {
    pub fn copy(&self) -> CopiedRequest {
        let mut headers = HashMap::new();

        for (key, value) in self.headers().iter() {
            headers.insert(key.to_str(), value.to_str());
        }

        CopiedRequest {
            headers: headers,
            method: self.method().map(|a| a.to_str()),
            url: self.url().map(|a| a.to_str()),
            http_version: self.http_version().map(|a| a.to_str()),
            query_string: self.query_string().map(|a| a.to_str()),
            remote_user: self.remote_user().map(|a| a.to_str()),
            remote_ip: self.remote_ip(),
            remote_port: self.remote_port(),
            is_ssl: self.is_ssl()
        }
    }

    pub fn get_header<S: Str>(&mut self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn count_headers(&self) -> uint {
        self.request_info.num_headers() as uint
    }

    pub fn method<'a>(&'a self) -> Option<&'a str> {
        self.request_info.method()
    }

    pub fn url<'a>(&'a self) -> Option<&'a str> {
        self.request_info.url()
    }

    pub fn http_version<'a>(&'a self) -> Option<&'a str> {
        self.request_info.http_version()
    }

    pub fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    pub fn remote_user<'a>(&'a self) -> Option<&'a str> {
        self.request_info.remote_user()
    }

    pub fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    pub fn remote_port(&self) -> u16 {
        self.request_info.remote_port() as u16
    }

    pub fn is_ssl(&self) -> bool {
        self.request_info.is_ssl()
    }

    pub fn headers<'a>(&'a self) -> Headers<'a> {
        Headers { conn: self.conn }
    }
}

pub struct Response {
    status: status::StatusCode,
    headers: HashMap<String, String>,
    body: Box<Reader + Send>,
}

impl Response {
    pub fn new<S: ToStatusCode, R: Reader + Send>(
        status: S,
        headers: HashMap<String, String>,
        body: R) -> Response
    {
        Response {
            status: status.to_status().unwrap(),
            headers: headers,
            body: box body,
        }
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = Request { conn: conn, request_info: info };
                Ok(Connection {
                    request: request
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for Request<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> Headers<'a> {
    pub fn find<S: Str>(&self, string: S) -> Option<String> {
        get_header(self.conn, string.as_slice())
    }

    pub fn iter<'a>(&'a self) -> HeaderIterator<'a> {
        HeaderIterator::new(self.conn)
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, &'a str)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, &'a str)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = headers.get(pos);
            self.position += 1;
            header.name().map(|name| (name, header.value().unwrap()))
        }
    }
}

pub trait Handler {
    fn call(&self, req: &mut Request) -> IoResult<Response>;
}

impl Handler for fn(&mut Request) -> IoResult<Response> {
    fn call(&self, req: &mut Request) -> IoResult<Response> {
        (*self)(req)
    }
}

// TODO: Why is 'static needed here and below?
pub struct Server(raw::Server<Box<Handler + 'static + Share>>);

impl Server {
    pub fn start<H: 'static + Handler + Share>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler>) -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let writer = &mut connection;

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(writer)),
            };
            let (code, string) = status.to_code();
            try!(write!(writer, "HTTP/1.1 {} {}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                try!(write!(writer, "{}: {}\r\n", key, value).map_err(|_| ()));
            }

            try!(write!(writer, "\r\n").map_err(|_| ()));
            try!(util::copy(&mut body, writer).map_err(|_| ()));

            Ok(())
        }

        let raw_callback = raw::ServerCallback::new(internal_handler,
                                                    box handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_str())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_str())
    }
}

#[cfg(test)]
mod test {
    use std::io::test::next_test_ip4;
    use super::{Server, Config, Request, Response, Handler};
    use std::io::IoResult;

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> IoResult<Response> {
                fail!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }
}
<|endoftext|>


<commit_before>

pub type Error = Box<::std::error::Error>;
pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Promise<T> {
    phantom_data : ::std::marker::PhantomData<T>,
    pub node : Box<PromiseNode>,
}

pub trait Event {

    // required methods

    fn fire(&mut self);

    // provided methods

    fn arm_breadth_first(&mut self) {}
    fn arm_depth_first(&mut self) {}
}

pub trait PromiseNode {
    /// Arms the given event when ready.
    fn on_ready(&self, event : &mut Event);

    fn set_self_pointer(&mut self) {}
    fn get(&self);
}

/// A promise that has already been resolved to an immediate value or error.
pub struct ImmediatePromiseNode<T> {
    result : ::std::result::Result<T, Error>,
}

impl <T> PromiseNode for ImmediatePromiseNode<T> {
    fn on_ready(&self, event : &mut Event) {
        event.arm_breadth_first();
    }
    fn get(&self) {

    }
}

<commit_msg>EventLoop<commit_after>#![allow(dead_code)]

pub type Error = Box<::std::error::Error>;
pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Promise<T> {
    phantom_data : ::std::marker::PhantomData<T>,
    pub node : Box<PromiseNode>,
}

pub trait Event {
    fn fire(&mut self);
}

pub trait PromiseNode {
    /// Arms the given event when ready.
    fn on_ready(&self, event : &mut Event);

    fn set_self_pointer(&mut self) {}
    fn get(&self);
}

/// A promise that has already been resolved to an immediate value or error.
pub struct ImmediatePromiseNode<T> {
    result : ::std::result::Result<T, Error>,
}

impl <T> PromiseNode for ImmediatePromiseNode<T> {
    fn on_ready(&self, event : &mut Event) {
        unimplemented!();
        //event.arm_breadth_first();
    }
    fn get(&self) {

    }
}

trait ErrorHandler {
    fn task_failed(error: Error);
}

struct TaskSetImpl {
    error_handler: Box<ErrorHandler>,
}

/// A Deque with an insertion point in the middle.
struct InsertDeque<T> {
    front: ::std::collections::VecDeque<T>,
    back: ::std::collections::VecDeque<T>,
}

/// A queue of events being executed in a loop.
struct EventLoop {
    daemons: TaskSetImpl,
    running: bool,
    last_runnable_state: bool,
    events: ::std::collections::VecDeque<Box<Event>>,
    depth_first_events: ::std::collections::VecDeque<Box<Event>>,
}

impl EventLoop {

    /// Run the even loop for `max_turn_count` turns or until there is nothing left to be done,
    /// whichever comes first. This never calls the `EventPort`'s `sleep()` or `poll()`. It will
    /// call the `EventPort`'s `set_runnable(false)` if the queue becomes empty.
    pub fn run(&mut self, max_turn_count : u32) {
        self.running = true;

        for _ in 0..max_turn_count {
            if !self.turn() {
                break;
            }
        }
    }

    fn turn(&mut self) -> bool {
        assert!(self.depth_first_events.is_empty());
        match self.events.pop_front() {
            None => return false,
            Some(mut event) => {
                // event->firing = true ?
                event.fire();
            }
        }
        while(!self.depth_first_events.is_empty()) {
            self.events.push_front(self.depth_first_events.pop_back().unwrap());
        }
        return true;
    }
}
<|endoftext|>