<commit_before>//! A batteries included runtime for applications using Tokio.
//!
//! Applications using Tokio require some runtime support in order to work:
//!
//! * A [reactor] to drive I/O resources.
//! * An [executor] to execute tasks that use these I/O resources.
//!
//! While it is possible to setup each component manually, this involves a bunch
//! of boilerplate.
//!
//! [`Runtime`] bundles all of these various runtime components into a single
//! handle that can be started and shutdown together, eliminating the necessary
//! boilerplate to run a Tokio application.
//!
//! Most applications wont need to use [`Runtime`] directly. Instead, they will
//! use the [`run`] function, which uses [`Runtime`] under the hood.
//!
//! Creating a [`Runtime`] does the following:
//!
//! * Spawn a background thread running a [`Reactor`] instance.
//! * Start a [`ThreadPool`] for executing futures.
//!
//! The thread pool uses a work-stealing strategy and is configured to start a
//! worker thread for each CPU core available on the system. This tends to be
//! the ideal setup for Tokio applications.
//!
//! # Usage
//!
//! Most applications will use the [`run`] function. This takes a future to
//! "seed" the application, blocking the thread until the runtime becomes
//! [idle].
//!
//! ```rust
//! # extern crate tokio;
//! # extern crate futures;
//! # use futures::{Future, Stream};
//! use tokio::net::TcpListener;
//!
//! # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
//! # unimplemented!();
//! # }
//! # fn dox() {
//! # let addr = "127.0.0.1:8080".parse().unwrap();
//! let listener = TcpListener::bind(&addr).unwrap();
//!
//! let server = listener.incoming()
//!     .map_err(|e| println!("error = {:?}", e))
//!     .for_each(|socket| {
//!         tokio::spawn(process(socket))
//!     });
//!
//! tokio::run(server);
//! # }
//! # pub fn main() {}
//! ```
//!
//! In this function, the `run` function blocks until the runtime becomes idle.
//! See [`shutdown_on_idle`][idle] for more shutdown details.
//!
//! From within the context of the runtime, additional tasks are spawned using
//! the [`tokio::spawn`] function. Futures spawned using this function will be
//! executed on the same thread pool used by the [`Runtime`].
//!
//! A [`Runtime`] instance can also be used directly.
//!
//! ```rust
//! # extern crate tokio;
//! # extern crate futures;
//! # use futures::{Future, Stream};
//! use tokio::runtime::Runtime;
//! use tokio::net::TcpListener;
//!
//! # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
//! # unimplemented!();
//! # }
//! # fn dox() {
//! # let addr = "127.0.0.1:8080".parse().unwrap();
//! let listener = TcpListener::bind(&addr).unwrap();
//!
//! let server = listener.incoming()
//!     .map_err(|e| println!("error = {:?}", e))
//!     .for_each(|socket| {
//!         tokio::spawn(process(socket))
//!     });
//!
//! // Create the runtime
//! let mut rt = Runtime::new().unwrap();
//!
//! // Spawn the server task
//! rt.spawn(server);
//!
//! // Wait until the runtime becomes idle and shut it down.
//! rt.shutdown_on_idle()
//!     .wait().unwrap();
//! # }
//! # pub fn main() {}
//! ```
//!
//! [reactor]: ../reactor/struct.Reactor.html
//! [executor]: https://tokio.rs/docs/getting-started/runtime-model/#executors
//! [`Runtime`]: struct.Runtime.html
//! [`ThreadPool`]: ../executor/thread_pool/struct.ThreadPool.html
//! [`run`]: fn.run.html
//! [idle]: struct.Runtime.html#method.shutdown_on_idle
//! [`tokio::spawn`]: ../executor/fn.spawn.html

use reactor::{Reactor, Handle, Background};

use tokio_threadpool::{self as threadpool, ThreadPool, Sender};
use futures::Poll;
use futures::future::{self, Future};

use std::{fmt, io};

/// Handle to the Tokio runtime.
///
/// The Tokio runtime includes a reactor as well as an executor for running
/// tasks.
///
/// See [module level][mod] documentation for more details.
///
/// [mod]: index.html
#[derive(Debug)]
pub struct Runtime {
    inner: Option<Inner>,
}

/// Executes futures on the runtime
///
/// All futures spawned using this executor will be submitted to the associated
/// Runtime's executor. This executor is usually a thread pool.
///
/// For more details, see the [module level](index.html) documentation.
#[derive(Debug, Clone)]
pub struct TaskExecutor {
    inner: Sender,
}

/// A future that resolves when the Tokio `Runtime` is shut down.
pub struct Shutdown {
    inner: Box<Future<Item = (), Error = ()> + Send>,
}

#[derive(Debug)]
struct Inner {
    /// Reactor running on a background thread.
    reactor: Background,

    /// Task execution pool.
    pool: ThreadPool,
}

// ===== impl Runtime =====

/// Start the Tokio runtime using the supplied future to bootstrap execution.
///
/// This function is used to bootstrap the execution of a Tokio application. It
/// does the following:
///
/// * Start the Tokio runtime using a default configuration.
/// * Spawn the given future onto the thread pool.
/// * Block the current thread until the runtime shuts down.
///
/// Note that the function will not return immediately once `future` has
/// completed. Instead it waits for the entire runtime to become idle.
///
/// See the [module level][mod] documentation for more details.
///
/// # Examples
///
/// ```rust
/// # extern crate tokio;
/// # extern crate futures;
/// # use futures::{Future, Stream};
/// use tokio::net::TcpListener;
///
/// # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
/// # unimplemented!();
/// # }
/// # fn dox() {
/// # let addr = "127.0.0.1:8080".parse().unwrap();
/// let listener = TcpListener::bind(&addr).unwrap();
///
/// let server = listener.incoming()
///     .map_err(|e| println!("error = {:?}", e))
///     .for_each(|socket| {
///         tokio::spawn(process(socket))
///     });
///
/// tokio::run(server);
/// # }
/// # pub fn main() {}
/// ```
///
/// # Panics
///
/// This function panics if called from the context of an executor.
///
/// [mod]: ../index.html
pub fn run<F>(future: F)
where F: Future<Item = (), Error = ()> + Send + 'static,
{
    let mut runtime = Runtime::new().unwrap();
    runtime.spawn(future);
    runtime.shutdown_on_idle().wait().unwrap();
}

impl Runtime {
    /// Create a new runtime instance with default configuration values.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    pub fn new() -> io::Result<Self> {
        // Spawn a reactor on a background thread.
        let reactor = Reactor::new()?.background()?;

        // Get a handle to the reactor.
        let handle = reactor.handle().clone();

        let pool = threadpool::Builder::new()
            .around_worker(move |w, enter| {
                ::tokio_reactor::with_default(&handle, enter, |_| {
                    w.run();
                });
            })
            .build();

        Ok(Runtime {
            inner: Some(Inner {
                reactor,
                pool,
            }),
        })
    }

    /// Return a reference to the reactor handle for this runtime instance.
    pub fn handle(&self) -> &Handle {
        self.inner().reactor.handle()
    }

    /// Return a handle to the runtime's executor.
    pub fn executor(&self) -> TaskExecutor {
        let inner = self.inner().pool.sender().clone();
        TaskExecutor { inner }
    }

    /// Spawn a future onto the Tokio runtime.
    ///
    /// This spawns the given future onto the runtime's executor, usually a
    /// thread pool. The thread pool is then responsible for polling the future
    /// until it completes.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate tokio;
    /// # extern crate futures;
    /// # use futures::{future, Future, Stream};
    /// use tokio::runtime::Runtime;
    ///
    /// # fn dox() {
    /// // Create the runtime
    /// let mut rt = Runtime::new().unwrap();
    ///
    /// // Spawn a future onto the runtime
    /// rt.spawn(future::lazy(|| {
    ///     println!("now running on a worker thread");
    ///     Ok(())
    /// }));
    /// # }
    /// # pub fn main() {}
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if the spawn fails. Failure occurs if the executor
    /// is currently at capacity and is unable to spawn a new future.
    pub fn spawn<F>(&mut self, future: F) -> &mut Self
    where F: Future<Item = (), Error = ()> + Send + 'static,
    {
        self.inner_mut().pool.sender().spawn(future).unwrap();
        self
    }

    /// Signals the runtime to shutdown once it becomes idle.
    ///
    /// Returns a future that completes once the shutdown operation has
    /// completed.
    ///
    /// This function can be used to perform a graceful shutdown of the runtime.
    ///
    /// The runtime enters an idle state once **all** of the following occur.
    ///
    /// * The thread pool has no tasks to execute, i.e., all tasks that were
    ///   spawned have completed.
    /// * The reactor is not managing any I/O resources.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    pub fn shutdown_on_idle(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();

        let inner = Box::new({
            let pool = inner.pool;
            let reactor = inner.reactor;

            pool.shutdown_on_idle().and_then(|_| {
                reactor.shutdown_on_idle()
            })
        });

        Shutdown { inner }
    }

    /// Signals the runtime to shutdown immediately.
    ///
    /// Returns a future that completes once the shutdown operation has
    /// completed.
    ///
    /// This function will forcibly shutdown the runtime, causing any
    /// in-progress work to become canceled. The shutdown steps are:
    ///
    /// * Drain any scheduled work queues.
    /// * Drop any futures that have not yet completed.
    /// * Drop the reactor.
    ///
    /// Once the reactor has dropped, any outstanding I/O resources bound to
    /// that reactor will no longer function. Calling any method on them will
    /// result in an error.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    pub fn shutdown_now(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();

        let inner = Box::new({
            let pool = inner.pool;
            let reactor = inner.reactor;

            pool.shutdown_now().and_then(|_| {
                reactor.shutdown_now()
            })
        });

        Shutdown { inner }
    }

    fn inner(&self) -> &Inner {
        self.inner.as_ref().unwrap()
    }

    fn inner_mut(&mut self) -> &mut Inner {
        self.inner.as_mut().unwrap()
    }
}

// ===== impl TaskExecutor =====

impl TaskExecutor {
    /// Spawn a future onto the Tokio runtime.
    ///
    /// This spawns the given future onto the runtime's executor, usually a
    /// thread pool. The thread pool is then responsible for polling the future
    /// until it completes.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate tokio;
    /// # extern crate futures;
    /// # use futures::{future, Future, Stream};
    /// use tokio::runtime::Runtime;
    ///
    /// # fn dox() {
    /// // Create the runtime
    /// let mut rt = Runtime::new().unwrap();
    /// let executor = rt.executor();
    ///
    /// // Spawn a future onto the runtime
    /// executor.spawn(future::lazy(|| {
    ///     println!("now running on a worker thread");
    ///     Ok(())
    /// }));
    /// # }
    /// # pub fn main() {}
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if the spawn fails. Failure occurs if the executor
    /// is currently at capacity and is unable to spawn a new future.
    pub fn spawn<F>(&self, future: F)
    where F: Future<Item = (), Error = ()> + Send + 'static,
    {
        self.inner.spawn(future).unwrap();
    }
}

impl<T> future::Executor<T> for TaskExecutor
where T: Future<Item = (), Error = ()> + Send + 'static,
{
    fn execute(&self, future: T) -> Result<(), future::ExecuteError<T>> {
        self.inner.execute(future)
    }
}

impl ::executor::Executor for TaskExecutor {
    fn spawn(&mut self, future: Box<Future<Item = (), Error = ()> + Send>)
        -> Result<(), ::executor::SpawnError>
    {
        self.inner.spawn(future)
    }
}

// ===== impl Shutdown =====

impl Future for Shutdown {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        try_ready!(self.inner.poll());
        Ok(().into())
    }
}

impl fmt::Debug for Shutdown {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Shutdown")
            .field("inner", &"Box<Future<Item = (), Error = ()>>")
            .finish()
    }
}
<commit_msg>Shutdown the runtime on drop (#214)<commit_after>//! A batteries included runtime for applications using Tokio.
//!
//! Applications using Tokio require some runtime support in order to work:
//!
//! * A [reactor] to drive I/O resources.
//! * An [executor] to execute tasks that use these I/O resources.
//!
//! While it is possible to setup each component manually, this involves a bunch
//! of boilerplate.
//!
//! [`Runtime`] bundles all of these various runtime components into a single
//! handle that can be started and shutdown together, eliminating the necessary
//! boilerplate to run a Tokio application.
//!
//! Most applications wont need to use [`Runtime`] directly. Instead, they will
//! use the [`run`] function, which uses [`Runtime`] under the hood.
//!
//! Creating a [`Runtime`] does the following:
//!
//! * Spawn a background thread running a [`Reactor`] instance.
//! * Start a [`ThreadPool`] for executing futures.
//!
//! The thread pool uses a work-stealing strategy and is configured to start a
//! worker thread for each CPU core available on the system. This tends to be
//! the ideal setup for Tokio applications.
//!
//! # Usage
//!
//! Most applications will use the [`run`] function. This takes a future to
//! "seed" the application, blocking the thread until the runtime becomes
//! [idle].
//!
//! ```rust
//! # extern crate tokio;
//! # extern crate futures;
//! # use futures::{Future, Stream};
//! use tokio::net::TcpListener;
//!
//! # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
//! # unimplemented!();
//! # }
//! # fn dox() {
//! # let addr = "127.0.0.1:8080".parse().unwrap();
//! let listener = TcpListener::bind(&addr).unwrap();
//!
//! let server = listener.incoming()
//!     .map_err(|e| println!("error = {:?}", e))
//!     .for_each(|socket| {
//!         tokio::spawn(process(socket))
//!     });
//!
//! tokio::run(server);
//! # }
//! # pub fn main() {}
//! ```
//!
//! In this function, the `run` function blocks until the runtime becomes idle.
//! See [`shutdown_on_idle`][idle] for more shutdown details.
//!
//! From within the context of the runtime, additional tasks are spawned using
//! the [`tokio::spawn`] function. Futures spawned using this function will be
//! executed on the same thread pool used by the [`Runtime`].
//!
//! A [`Runtime`] instance can also be used directly.
//!
//! ```rust
//! # extern crate tokio;
//! # extern crate futures;
//! # use futures::{Future, Stream};
//! use tokio::runtime::Runtime;
//! use tokio::net::TcpListener;
//!
//! # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
//! # unimplemented!();
//! # }
//! # fn dox() {
//! # let addr = "127.0.0.1:8080".parse().unwrap();
//! let listener = TcpListener::bind(&addr).unwrap();
//!
//! let server = listener.incoming()
//!     .map_err(|e| println!("error = {:?}", e))
//!     .for_each(|socket| {
//!         tokio::spawn(process(socket))
//!     });
//!
//! // Create the runtime
//! let mut rt = Runtime::new().unwrap();
//!
//! // Spawn the server task
//! rt.spawn(server);
//!
//! // Wait until the runtime becomes idle and shut it down.
//! rt.shutdown_on_idle()
//!     .wait().unwrap();
//! # }
//! # pub fn main() {}
//! ```
//!
//! [reactor]: ../reactor/struct.Reactor.html
//! [executor]: https://tokio.rs/docs/getting-started/runtime-model/#executors
//! [`Runtime`]: struct.Runtime.html
//! [`ThreadPool`]: ../executor/thread_pool/struct.ThreadPool.html
//! [`run`]: fn.run.html
//! [idle]: struct.Runtime.html#method.shutdown_on_idle
//! [`tokio::spawn`]: ../executor/fn.spawn.html

use reactor::{Reactor, Handle, Background};

use tokio_threadpool::{self as threadpool, ThreadPool, Sender};
use futures::Poll;
use futures::future::{self, Future};

use std::{fmt, io};

/// Handle to the Tokio runtime.
///
/// The Tokio runtime includes a reactor as well as an executor for running
/// tasks.
///
/// See [module level][mod] documentation for more details.
///
/// [mod]: index.html
#[derive(Debug)]
pub struct Runtime {
    inner: Option<Inner>,
}

/// Executes futures on the runtime
///
/// All futures spawned using this executor will be submitted to the associated
/// Runtime's executor. This executor is usually a thread pool.
///
/// For more details, see the [module level](index.html) documentation.
#[derive(Debug, Clone)]
pub struct TaskExecutor {
    inner: Sender,
}

/// A future that resolves when the Tokio `Runtime` is shut down.
pub struct Shutdown {
    inner: Box<Future<Item = (), Error = ()> + Send>,
}

#[derive(Debug)]
struct Inner {
    /// Reactor running on a background thread.
    reactor: Background,

    /// Task execution pool.
    pool: ThreadPool,
}

// ===== impl Runtime =====

/// Start the Tokio runtime using the supplied future to bootstrap execution.
///
/// This function is used to bootstrap the execution of a Tokio application. It
/// does the following:
///
/// * Start the Tokio runtime using a default configuration.
/// * Spawn the given future onto the thread pool.
/// * Block the current thread until the runtime shuts down.
///
/// Note that the function will not return immediately once `future` has
/// completed. Instead it waits for the entire runtime to become idle.
///
/// See the [module level][mod] documentation for more details.
///
/// # Examples
///
/// ```rust
/// # extern crate tokio;
/// # extern crate futures;
/// # use futures::{Future, Stream};
/// use tokio::net::TcpListener;
///
/// # fn process<T>(_: T) -> Box<Future<Item = (), Error = ()> + Send> {
/// # unimplemented!();
/// # }
/// # fn dox() {
/// # let addr = "127.0.0.1:8080".parse().unwrap();
/// let listener = TcpListener::bind(&addr).unwrap();
///
/// let server = listener.incoming()
///     .map_err(|e| println!("error = {:?}", e))
///     .for_each(|socket| {
///         tokio::spawn(process(socket))
///     });
///
/// tokio::run(server);
/// # }
/// # pub fn main() {}
/// ```
///
/// # Panics
///
/// This function panics if called from the context of an executor.
///
/// [mod]: ../index.html
pub fn run<F>(future: F)
where F: Future<Item = (), Error = ()> + Send + 'static,
{
    let mut runtime = Runtime::new().unwrap();
    runtime.spawn(future);
    runtime.shutdown_on_idle().wait().unwrap();
}

impl Runtime {
    /// Create a new runtime instance with default configuration values.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    pub fn new() -> io::Result<Self> {
        // Spawn a reactor on a background thread.
        let reactor = Reactor::new()?.background()?;

        // Get a handle to the reactor.
        let handle = reactor.handle().clone();

        let pool = threadpool::Builder::new()
            .around_worker(move |w, enter| {
                ::tokio_reactor::with_default(&handle, enter, |_| {
                    w.run();
                });
            })
            .build();

        Ok(Runtime {
            inner: Some(Inner {
                reactor,
                pool,
            }),
        })
    }

    /// Return a reference to the reactor handle for this runtime instance.
    pub fn handle(&self) -> &Handle {
        self.inner().reactor.handle()
    }

    /// Return a handle to the runtime's executor.
    pub fn executor(&self) -> TaskExecutor {
        let inner = self.inner().pool.sender().clone();
        TaskExecutor { inner }
    }

    /// Spawn a future onto the Tokio runtime.
    ///
    /// This spawns the given future onto the runtime's executor, usually a
    /// thread pool. The thread pool is then responsible for polling the future
    /// until it completes.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate tokio;
    /// # extern crate futures;
    /// # use futures::{future, Future, Stream};
    /// use tokio::runtime::Runtime;
    ///
    /// # fn dox() {
    /// // Create the runtime
    /// let mut rt = Runtime::new().unwrap();
    ///
    /// // Spawn a future onto the runtime
    /// rt.spawn(future::lazy(|| {
    ///     println!("now running on a worker thread");
    ///     Ok(())
    /// }));
    /// # }
    /// # pub fn main() {}
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if the spawn fails. Failure occurs if the executor
    /// is currently at capacity and is unable to spawn a new future.
    pub fn spawn<F>(&mut self, future: F) -> &mut Self
    where F: Future<Item = (), Error = ()> + Send + 'static,
    {
        self.inner_mut().pool.sender().spawn(future).unwrap();
        self
    }

    /// Signals the runtime to shutdown once it becomes idle.
    ///
    /// Returns a future that completes once the shutdown operation has
    /// completed.
    ///
    /// This function can be used to perform a graceful shutdown of the runtime.
    ///
    /// The runtime enters an idle state once **all** of the following occur.
    ///
    /// * The thread pool has no tasks to execute, i.e., all tasks that were
    ///   spawned have completed.
    /// * The reactor is not managing any I/O resources.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    pub fn shutdown_on_idle(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();

        let inner = Box::new({
            let pool = inner.pool;
            let reactor = inner.reactor;

            pool.shutdown_on_idle().and_then(|_| {
                reactor.shutdown_on_idle()
            })
        });

        Shutdown { inner }
    }

    /// Signals the runtime to shutdown immediately.
    ///
    /// Returns a future that completes once the shutdown operation has
    /// completed.
    ///
    /// This function will forcibly shutdown the runtime, causing any
    /// in-progress work to become canceled. The shutdown steps are:
    ///
    /// * Drain any scheduled work queues.
    /// * Drop any futures that have not yet completed.
    /// * Drop the reactor.
    ///
    /// Once the reactor has dropped, any outstanding I/O resources bound to
    /// that reactor will no longer function. Calling any method on them will
    /// result in an error.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    pub fn shutdown_now(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();
        Shutdown::shutdown_now(inner)
    }

    fn inner(&self) -> &Inner {
        self.inner.as_ref().unwrap()
    }

    fn inner_mut(&mut self) -> &mut Inner {
        self.inner.as_mut().unwrap()
    }
}

impl Drop for Runtime {
    fn drop(&mut self) {
        if let Some(inner) = self.inner.take() {
            let shutdown = Shutdown::shutdown_now(inner);
            let _ = shutdown.wait();
        }
    }
}

// ===== impl TaskExecutor =====

impl TaskExecutor {
    /// Spawn a future onto the Tokio runtime.
    ///
    /// This spawns the given future onto the runtime's executor, usually a
    /// thread pool. The thread pool is then responsible for polling the future
    /// until it completes.
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// [mod]: index.html
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate tokio;
    /// # extern crate futures;
    /// # use futures::{future, Future, Stream};
    /// use tokio::runtime::Runtime;
    ///
    /// # fn dox() {
    /// // Create the runtime
    /// let mut rt = Runtime::new().unwrap();
    /// let executor = rt.executor();
    ///
    /// // Spawn a future onto the runtime
    /// executor.spawn(future::lazy(|| {
    ///     println!("now running on a worker thread");
    ///     Ok(())
    /// }));
    /// # }
    /// # pub fn main() {}
    /// ```
    ///
    /// # Panics
    ///
    /// This function panics if the spawn fails. Failure occurs if the executor
    /// is currently at capacity and is unable to spawn a new future.
    pub fn spawn<F>(&self, future: F)
    where F: Future<Item = (), Error = ()> + Send + 'static,
    {
        self.inner.spawn(future).unwrap();
    }
}

impl<T> future::Executor<T> for TaskExecutor
where T: Future<Item = (), Error = ()> + Send + 'static,
{
    fn execute(&self, future: T) -> Result<(), future::ExecuteError<T>> {
        self.inner.execute(future)
    }
}

impl ::executor::Executor for TaskExecutor {
    fn spawn(&mut self, future: Box<Future<Item = (), Error = ()> + Send>)
        -> Result<(), ::executor::SpawnError>
    {
        self.inner.spawn(future)
    }
}

// ===== impl Shutdown =====

impl Shutdown {
    fn shutdown_now(inner: Inner) -> Self {
        let inner = Box::new({
            let pool = inner.pool;
            let reactor = inner.reactor;

            pool.shutdown_now().and_then(|_| {
                reactor.shutdown_now()
                    .then(|_| {
                        Ok(())
                    })
            })
        });

        Shutdown { inner }
    }
}

impl Future for Shutdown {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<(), ()> {
        try_ready!(self.inner.poll());
        Ok(().into())
    }
}

impl fmt::Debug for Shutdown {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Shutdown")
            .field("inner", &"Box<Future<Item = (), Error = ()>>")
            .finish()
    }
}
<|endoftext|>


<commit_before>use std::io::Result;

use fleetspeak::Packet;

use crate::action::Response;

pub struct Session {
    id: String,
    next_response_id: u64,
}

impl Session {

    pub fn known<S: Into<String>>(id: S) -> Session {
        Session {
            id: id.into(),
            next_response_id: 0,
        }
    }

    // TODO: Handle errors properly.
    pub fn reply<R: Response>(&mut self, response: R) -> Result<()> {
        let mut data = Vec::new();
        prost::Message::encode(&response.into_proto(), &mut data)?;

        let message = rrg_proto::GrrMessage {
            session_id: Some(self.id.clone()),
            response_id: Some(self.next_response_id),
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        };

        self.next_response_id += 1;

        fleetspeak::send(Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: message,
        })?;

        Ok(())
    }
}
<commit_msg>Create a more idiomatic wrapper for GRR messages.<commit_after>use std::io::Result;

use fleetspeak::Packet;

use crate::action::Response;

pub struct Session {
    id: String,
    next_response_id: u64,
}

impl Session {

    pub fn known<S: Into<String>>(id: S) -> Session {
        Session {
            id: id.into(),
            next_response_id: 0,
        }
    }

    // TODO: Handle errors properly.
    pub fn reply<R: Response>(&mut self, response: R) -> Result<()> {
        Message {
            session_id: self.id.clone(),
            response_id: self.next_response_id,
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

struct Message<R: Response> {
    session_id: String,
    response_id: u64,
    data: R,
}

impl<R: Response> Message<R> {

    // TODO: Handle errors properly.
    fn send(self) -> Result<()> {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        let proto = rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: Some(self.response_id),
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        };

        fleetspeak::send(Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: proto,
        })?;

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


<commit_before>use crypto::digest::Digest;
use crypto::sha1::Sha1;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use eventual;
use eventual::Future;
use eventual::Async;
use protobuf::{self, Message};
use rand::thread_rng;
use std::io::{Read, Write, Cursor};
use std::result::Result;
use std::sync::{Mutex, RwLock, Arc, mpsc};

use album_cover::AlbumCover;
use apresolve::apresolve;
use audio_key::{AudioKeyManager, AudioKey, AudioKeyError};
use audio_file::AudioFile;
use authentication::Credentials;
use cache::Cache;
use connection::{self, PlainConnection, CipherConnection};
use diffie_hellman::DHLocalKeys;
use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
use metadata::{MetadataManager, MetadataRef, MetadataTrait};
use protocol;
use stream::StreamManager;
use util::{self, SpotifyId, FileId, ReadSeek};
use version;

use stream;

#[derive(Clone, Copy)]
pub enum Bitrate {
    Bitrate96,
    Bitrate160,
    Bitrate320,
}

pub struct Config {
    pub user_agent: String,
    pub device_name: String,
    pub bitrate: Bitrate,
    pub onstart: Option<String>,
    pub onstop: Option<String>,
}

pub struct SessionData {
    country: String,
    canonical_username: String,
}

pub struct SessionInternal {
    config: Config,
    device_id: String,
    data: RwLock<SessionData>,

    cache: Box<Cache + Send + Sync>,
    mercury: Mutex<MercuryManager>,
    metadata: Mutex<MetadataManager>,
    stream: Mutex<StreamManager>,
    audio_key: Mutex<AudioKeyManager>,
    rx_connection: Mutex<Option<CipherConnection>>,
    tx_connection: Mutex<Option<CipherConnection>>,
}

#[derive(Clone)]
pub struct Session(pub Arc<SessionInternal>);

impl Session {
    pub fn new(config: Config, cache: Box<Cache + Send + Sync>) -> Session {
        let device_id = {
            let mut h = Sha1::new();
            h.input_str(&config.device_name);
            h.result_str()
        };

        Session(Arc::new(SessionInternal {
            config: config,
            device_id: device_id,
            data: RwLock::new(SessionData {
                country: String::new(),
                canonical_username: String::new(),
            }),

            rx_connection: Mutex::new(None),
            tx_connection: Mutex::new(None),

            cache: cache,
            mercury: Mutex::new(MercuryManager::new()),
            metadata: Mutex::new(MetadataManager::new()),
            stream: Mutex::new(StreamManager::new()),
            audio_key: Mutex::new(AudioKeyManager::new()),
        }))
    }

    fn connect(&self) -> CipherConnection {
        let local_keys = DHLocalKeys::random(&mut thread_rng());

        let ap = apresolve();

        info!("Connecting to AP {}", ap);
        let mut connection = PlainConnection::connect(&ap).unwrap();

        let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
            build_info => {
                product: protocol::keyexchange::Product::PRODUCT_PARTNER,
                platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
                version: 0x10800000000,
            },
            cryptosuites_supported => [
                protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
            ],
            login_crypto_hello.diffie_hellman => {
                gc: local_keys.public_key(),
                server_keys_known: 1,
            },
            client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
            padding: vec![0x1e],
        });

        let init_client_packet = connection.send_packet_prefix(&[0, 4],
                                                               &request.write_to_bytes().unwrap())
                                           .unwrap();
        let init_server_packet = connection.recv_packet().unwrap();

        let response: protocol::keyexchange::APResponseMessage =
            protobuf::parse_from_bytes(&init_server_packet[4..]).unwrap();

        let remote_key = response.get_challenge()
                                 .get_login_crypto_challenge()
                                 .get_diffie_hellman()
                                 .get_gs();

        let shared_secret = local_keys.shared_secret(remote_key);
        let (challenge, send_key, recv_key) = {
            let mut data = Vec::with_capacity(0x64);
            let mut mac = Hmac::new(Sha1::new(), &shared_secret);

            for i in 1..6 {
                mac.input(&init_client_packet);
                mac.input(&init_server_packet);
                mac.input(&[i]);
                data.write(&mac.result().code()).unwrap();
                mac.reset();
            }

            mac = Hmac::new(Sha1::new(), &data[..0x14]);
            mac.input(&init_client_packet);
            mac.input(&init_server_packet);

            (mac.result().code().to_vec(),
             data[0x14..0x34].to_vec(),
             data[0x34..0x54].to_vec())
        };

        let packet = protobuf_init!(protocol::keyexchange::ClientResponsePlaintext::new(), {
            login_crypto_response.diffie_hellman => {
                hmac: challenge
            },
            pow_response => {},
            crypto_response => {},
        });

        connection.send_packet(&packet.write_to_bytes().unwrap()).unwrap();

        CipherConnection::new(connection.into_stream(),
                              &send_key,
                              &recv_key)
    }

    pub fn login(&self, credentials: Credentials) -> Result<Credentials, ()> {
        let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
            login_credentials => {
                username: credentials.username,
                typ: credentials.auth_type,
                auth_data: credentials.auth_data,
            },
            system_info => {
                cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
                os: protocol::authentication::Os::OS_UNKNOWN,
                system_information_string: "librespot".to_owned(),
                device_id: self.device_id().to_owned(),
            },
            version_string: version::version_string(),
        });

        let mut connection = self.connect();
        connection.send_packet(0xab, &packet.write_to_bytes().unwrap()).unwrap();
        let (cmd, data) = connection.recv_packet().unwrap();

        match cmd {
            0xac => {
                let welcome_data: protocol::authentication::APWelcome =
                    protobuf::parse_from_bytes(&data).unwrap();

                let username = welcome_data.get_canonical_username().to_owned();
                self.0.data.write().unwrap().canonical_username = username.clone();
                *self.0.rx_connection.lock().unwrap() = Some(connection.clone());
                *self.0.tx_connection.lock().unwrap() = Some(connection);

                info!("Authenticated !");

                let reusable_credentials = Credentials {
                    username: username,
                    auth_type: welcome_data.get_reusable_auth_credentials_type(),
                    auth_data: welcome_data.get_reusable_auth_credentials().to_owned(),
                };

                self.0.cache.put_credentials(&reusable_credentials);

                Ok(reusable_credentials)
            }

            0xad => {
                let msg: protocol::keyexchange::APLoginFailed =
                    protobuf::parse_from_bytes(&data).unwrap();
                error!("Authentication failed, {:?}", msg);
                Err(())
            }
            _ => {
                error!("Unexpected message {:x}", cmd);
                Err(())
            }
        }
    }

    pub fn poll(&self) {
        let (cmd, data) = self.recv();

        match cmd {
            0x4 => self.send_packet(0x49, &data).unwrap(),
            0x4a => (),
            0x9 | 0xa => self.0.stream.lock().unwrap().handle(cmd, data, self),
            0xd | 0xe => self.0.audio_key.lock().unwrap().handle(cmd, data, self),
            0x1b => {
                self.0.data.write().unwrap().country = String::from_utf8(data).unwrap();
            }
            0xb2...0xb6 => self.0.mercury.lock().unwrap().handle(cmd, data, self),
            _ => (),
        }
    }

    pub fn recv(&self) -> (u8, Vec<u8>) {
        self.0.rx_connection.lock().unwrap().as_mut().unwrap().recv_packet().unwrap()
    }

    pub fn send_packet(&self, cmd: u8, data: &[u8]) -> connection::Result<()> {
        self.0.tx_connection.lock().unwrap().as_mut().unwrap().send_packet(cmd, data)
    }

    pub fn audio_key(&self, track: SpotifyId, file_id: FileId) -> Future<AudioKey, AudioKeyError> {
        self.0.cache
            .get_audio_key(track, file_id)
            .map(Future::of)
            .unwrap_or_else(|| {
                let self_ = self.clone();
                self.0.audio_key.lock().unwrap()
                    .request(self, track, file_id)
                    .map(move |key| {
                        self_.0.cache.put_audio_key(track, file_id, key);
                        key
                    })
            })
    }

    pub fn audio_file(&self, file_id: FileId) -> Box<ReadSeek> {
        self.0.cache
            .get_file(file_id)
            .unwrap_or_else(|| {
                let (audio_file, complete_rx) = AudioFile::new(self, file_id);

                let self_ = self.clone();
                complete_rx.map(move |mut complete_file| {
                    self_.0.cache.put_file(file_id, &mut complete_file)
                }).fire();

                Box::new(audio_file.await().unwrap())
            })
    }

    pub fn album_cover(&self, file_id: FileId) -> eventual::Future<Vec<u8>, ()> {
        self.0.cache
            .get_file(file_id)
            .map(|mut f| {
                let mut data = Vec::new();
                f.read_to_end(&mut data).unwrap();
                Future::of(data)
            })
            .unwrap_or_else(|| {
                  let self_ = self.clone();
                  AlbumCover::get(file_id, self)
                      .map(move |data| {
                          self_.0.cache.put_file(file_id, &mut Cursor::new(&data));
                          data
                      })
              })
    }

    pub fn stream(&self, handler: Box<stream::Handler>) {
        self.0.stream.lock().unwrap().create(handler, self)
    }

    pub fn metadata<T: MetadataTrait>(&self, id: SpotifyId) -> MetadataRef<T> {
        self.0.metadata.lock().unwrap().get(self, id)
    }

    pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse, ()> {
        self.0.mercury.lock().unwrap().request(self, req)
    }

    pub fn mercury_sub(&self, uri: String) -> mpsc::Receiver<MercuryResponse> {
        self.0.mercury.lock().unwrap().subscribe(self, uri)
    }

    pub fn cache(&self) -> &Cache {
        self.0.cache.as_ref()
    }

    pub fn config(&self) -> &Config {
        &self.0.config
    }

    pub fn username(&self) -> String {
        self.0.data.read().unwrap().canonical_username.clone()
    }

    pub fn country(&self) -> String {
        self.0.data.read().unwrap().country.clone()
    }

    pub fn device_id(&self) -> &str {
        &self.0.device_id
    }
}

pub trait PacketHandler {
    fn handle(&mut self, cmd: u8, data: Vec<u8>, session: &Session);
}
<commit_msg>Add standard traits to Bitrate.<commit_after>use crypto::digest::Digest;
use crypto::sha1::Sha1;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use eventual;
use eventual::Future;
use eventual::Async;
use protobuf::{self, Message};
use rand::thread_rng;
use std::io::{Read, Write, Cursor};
use std::result::Result;
use std::sync::{Mutex, RwLock, Arc, mpsc};

use album_cover::AlbumCover;
use apresolve::apresolve;
use audio_key::{AudioKeyManager, AudioKey, AudioKeyError};
use audio_file::AudioFile;
use authentication::Credentials;
use cache::Cache;
use connection::{self, PlainConnection, CipherConnection};
use diffie_hellman::DHLocalKeys;
use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
use metadata::{MetadataManager, MetadataRef, MetadataTrait};
use protocol;
use stream::StreamManager;
use util::{self, SpotifyId, FileId, ReadSeek};
use version;

use stream;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub enum Bitrate {
    Bitrate96,
    Bitrate160,
    Bitrate320,
}

pub struct Config {
    pub user_agent: String,
    pub device_name: String,
    pub bitrate: Bitrate,
    pub onstart: Option<String>,
    pub onstop: Option<String>,
}

pub struct SessionData {
    country: String,
    canonical_username: String,
}

pub struct SessionInternal {
    config: Config,
    device_id: String,
    data: RwLock<SessionData>,

    cache: Box<Cache + Send + Sync>,
    mercury: Mutex<MercuryManager>,
    metadata: Mutex<MetadataManager>,
    stream: Mutex<StreamManager>,
    audio_key: Mutex<AudioKeyManager>,
    rx_connection: Mutex<Option<CipherConnection>>,
    tx_connection: Mutex<Option<CipherConnection>>,
}

#[derive(Clone)]
pub struct Session(pub Arc<SessionInternal>);

impl Session {
    pub fn new(config: Config, cache: Box<Cache + Send + Sync>) -> Session {
        let device_id = {
            let mut h = Sha1::new();
            h.input_str(&config.device_name);
            h.result_str()
        };

        Session(Arc::new(SessionInternal {
            config: config,
            device_id: device_id,
            data: RwLock::new(SessionData {
                country: String::new(),
                canonical_username: String::new(),
            }),

            rx_connection: Mutex::new(None),
            tx_connection: Mutex::new(None),

            cache: cache,
            mercury: Mutex::new(MercuryManager::new()),
            metadata: Mutex::new(MetadataManager::new()),
            stream: Mutex::new(StreamManager::new()),
            audio_key: Mutex::new(AudioKeyManager::new()),
        }))
    }

    fn connect(&self) -> CipherConnection {
        let local_keys = DHLocalKeys::random(&mut thread_rng());

        let ap = apresolve();

        info!("Connecting to AP {}", ap);
        let mut connection = PlainConnection::connect(&ap).unwrap();

        let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
            build_info => {
                product: protocol::keyexchange::Product::PRODUCT_PARTNER,
                platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
                version: 0x10800000000,
            },
            cryptosuites_supported => [
                protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
            ],
            login_crypto_hello.diffie_hellman => {
                gc: local_keys.public_key(),
                server_keys_known: 1,
            },
            client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
            padding: vec![0x1e],
        });

        let init_client_packet = connection.send_packet_prefix(&[0, 4],
                                                               &request.write_to_bytes().unwrap())
                                           .unwrap();
        let init_server_packet = connection.recv_packet().unwrap();

        let response: protocol::keyexchange::APResponseMessage =
            protobuf::parse_from_bytes(&init_server_packet[4..]).unwrap();

        let remote_key = response.get_challenge()
                                 .get_login_crypto_challenge()
                                 .get_diffie_hellman()
                                 .get_gs();

        let shared_secret = local_keys.shared_secret(remote_key);
        let (challenge, send_key, recv_key) = {
            let mut data = Vec::with_capacity(0x64);
            let mut mac = Hmac::new(Sha1::new(), &shared_secret);

            for i in 1..6 {
                mac.input(&init_client_packet);
                mac.input(&init_server_packet);
                mac.input(&[i]);
                data.write(&mac.result().code()).unwrap();
                mac.reset();
            }

            mac = Hmac::new(Sha1::new(), &data[..0x14]);
            mac.input(&init_client_packet);
            mac.input(&init_server_packet);

            (mac.result().code().to_vec(),
             data[0x14..0x34].to_vec(),
             data[0x34..0x54].to_vec())
        };

        let packet = protobuf_init!(protocol::keyexchange::ClientResponsePlaintext::new(), {
            login_crypto_response.diffie_hellman => {
                hmac: challenge
            },
            pow_response => {},
            crypto_response => {},
        });

        connection.send_packet(&packet.write_to_bytes().unwrap()).unwrap();

        CipherConnection::new(connection.into_stream(),
                              &send_key,
                              &recv_key)
    }

    pub fn login(&self, credentials: Credentials) -> Result<Credentials, ()> {
        let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
            login_credentials => {
                username: credentials.username,
                typ: credentials.auth_type,
                auth_data: credentials.auth_data,
            },
            system_info => {
                cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
                os: protocol::authentication::Os::OS_UNKNOWN,
                system_information_string: "librespot".to_owned(),
                device_id: self.device_id().to_owned(),
            },
            version_string: version::version_string(),
        });

        let mut connection = self.connect();
        connection.send_packet(0xab, &packet.write_to_bytes().unwrap()).unwrap();
        let (cmd, data) = connection.recv_packet().unwrap();

        match cmd {
            0xac => {
                let welcome_data: protocol::authentication::APWelcome =
                    protobuf::parse_from_bytes(&data).unwrap();

                let username = welcome_data.get_canonical_username().to_owned();
                self.0.data.write().unwrap().canonical_username = username.clone();
                *self.0.rx_connection.lock().unwrap() = Some(connection.clone());
                *self.0.tx_connection.lock().unwrap() = Some(connection);

                info!("Authenticated !");

                let reusable_credentials = Credentials {
                    username: username,
                    auth_type: welcome_data.get_reusable_auth_credentials_type(),
                    auth_data: welcome_data.get_reusable_auth_credentials().to_owned(),
                };

                self.0.cache.put_credentials(&reusable_credentials);

                Ok(reusable_credentials)
            }

            0xad => {
                let msg: protocol::keyexchange::APLoginFailed =
                    protobuf::parse_from_bytes(&data).unwrap();
                error!("Authentication failed, {:?}", msg);
                Err(())
            }
            _ => {
                error!("Unexpected message {:x}", cmd);
                Err(())
            }
        }
    }

    pub fn poll(&self) {
        let (cmd, data) = self.recv();

        match cmd {
            0x4 => self.send_packet(0x49, &data).unwrap(),
            0x4a => (),
            0x9 | 0xa => self.0.stream.lock().unwrap().handle(cmd, data, self),
            0xd | 0xe => self.0.audio_key.lock().unwrap().handle(cmd, data, self),
            0x1b => {
                self.0.data.write().unwrap().country = String::from_utf8(data).unwrap();
            }
            0xb2...0xb6 => self.0.mercury.lock().unwrap().handle(cmd, data, self),
            _ => (),
        }
    }

    pub fn recv(&self) -> (u8, Vec<u8>) {
        self.0.rx_connection.lock().unwrap().as_mut().unwrap().recv_packet().unwrap()
    }

    pub fn send_packet(&self, cmd: u8, data: &[u8]) -> connection::Result<()> {
        self.0.tx_connection.lock().unwrap().as_mut().unwrap().send_packet(cmd, data)
    }

    pub fn audio_key(&self, track: SpotifyId, file_id: FileId) -> Future<AudioKey, AudioKeyError> {
        self.0.cache
            .get_audio_key(track, file_id)
            .map(Future::of)
            .unwrap_or_else(|| {
                let self_ = self.clone();
                self.0.audio_key.lock().unwrap()
                    .request(self, track, file_id)
                    .map(move |key| {
                        self_.0.cache.put_audio_key(track, file_id, key);
                        key
                    })
            })
    }

    pub fn audio_file(&self, file_id: FileId) -> Box<ReadSeek> {
        self.0.cache
            .get_file(file_id)
            .unwrap_or_else(|| {
                let (audio_file, complete_rx) = AudioFile::new(self, file_id);

                let self_ = self.clone();
                complete_rx.map(move |mut complete_file| {
                    self_.0.cache.put_file(file_id, &mut complete_file)
                }).fire();

                Box::new(audio_file.await().unwrap())
            })
    }

    pub fn album_cover(&self, file_id: FileId) -> eventual::Future<Vec<u8>, ()> {
        self.0.cache
            .get_file(file_id)
            .map(|mut f| {
                let mut data = Vec::new();
                f.read_to_end(&mut data).unwrap();
                Future::of(data)
            })
            .unwrap_or_else(|| {
                  let self_ = self.clone();
                  AlbumCover::get(file_id, self)
                      .map(move |data| {
                          self_.0.cache.put_file(file_id, &mut Cursor::new(&data));
                          data
                      })
              })
    }

    pub fn stream(&self, handler: Box<stream::Handler>) {
        self.0.stream.lock().unwrap().create(handler, self)
    }

    pub fn metadata<T: MetadataTrait>(&self, id: SpotifyId) -> MetadataRef<T> {
        self.0.metadata.lock().unwrap().get(self, id)
    }

    pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse, ()> {
        self.0.mercury.lock().unwrap().request(self, req)
    }

    pub fn mercury_sub(&self, uri: String) -> mpsc::Receiver<MercuryResponse> {
        self.0.mercury.lock().unwrap().subscribe(self, uri)
    }

    pub fn cache(&self) -> &Cache {
        self.0.cache.as_ref()
    }

    pub fn config(&self) -> &Config {
        &self.0.config
    }

    pub fn username(&self) -> String {
        self.0.data.read().unwrap().canonical_username.clone()
    }

    pub fn country(&self) -> String {
        self.0.data.read().unwrap().country.clone()
    }

    pub fn device_id(&self) -> &str {
        &self.0.device_id
    }
}

pub trait PacketHandler {
    fn handle(&mut self, cmd: u8, data: Vec<u8>, session: &Session);
}
<|endoftext|>


<commit_before>//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! *This module is available if Syn is built with both the `"parsing"` and
//! `"printing"` features.*
//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```edition2018
//! # extern crate proc_macro;
//! #
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//! use quote::quote_spanned;
//! use syn::Type;
//! use syn::spanned::Spanned;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let assert_sync = quote_spanned! {ty.span()=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type.

use proc_macro2::Span;
use quote::spanned::Spanned as ToTokens;

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate, as well as for `Span` itself.
///
/// [`ToTokens`]: quote::ToTokens
///
/// See the [module documentation] for an example.
///
/// [module documentation]: self
///
/// *This trait is available if Syn is built with both the `"parsing"` and
/// `"printing"` features.*
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: proc_macro2::Span::call_site
    fn span(&self) -> Span;
}

impl<T: ?Sized + ToTokens> Spanned for T {
    fn span(&self) -> Span {
        self.__span()
    }
}
<commit_msg>Document behavior of Spanned when we can't join spans<commit_after>//! A trait that can provide the `Span` of the complete contents of a syntax
//! tree node.
//!
//! *This module is available if Syn is built with both the `"parsing"` and
//! `"printing"` features.*
//!
//!

//!
//! # Example
//!
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
//! of a struct for which we are deriving a trait implementation, and we need to
//! be able to pass a reference to one of those fields across threads.
//!
//! [`Type`]: ../enum.Type.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//!
//! If the field type does *not* implement `Sync` as required, we want the
//! compiler to report an error pointing out exactly which type it was.
//!
//! The following macro code takes a variable `ty` of type `Type` and produces a
//! static assertion that `Sync` is implemented for that type.
//!
//! ```edition2018
//! # extern crate proc_macro;
//! #
//! use proc_macro::TokenStream;
//! use proc_macro2::Span;
//! use quote::quote_spanned;
//! use syn::Type;
//! use syn::spanned::Spanned;
//!
//! # const IGNORE_TOKENS: &str = stringify! {
//! #[proc_macro_derive(MyMacro)]
//! # };
//! pub fn my_macro(input: TokenStream) -> TokenStream {
//!     # let ty = get_a_type();
//!     /* ... */
//!
//!     let assert_sync = quote_spanned! {ty.span()=>
//!         struct _AssertSync where #ty: Sync;
//!     };
//!
//!     /* ... */
//!     # input
//! }
//! #
//! # fn get_a_type() -> Type {
//! #     unimplemented!()
//! # }
//! ```
//!
//! By inserting this `assert_sync` fragment into the output code generated by
//! our macro, the user's code will fail to compile if `ty` does not implement
//! `Sync`. The errors they would see look like the following.
//!
//! ```text
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
//!   --> src/main.rs:10:21
//!    |
//! 10 |     bad_field: *const i32,
//!    |                ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
//! ```
//!
//! In this technique, using the `Type`'s span for the error message makes the
//! error appear in the correct place underlining the right type.
//!
//!

//!
//! # Limitations
//!
//! The underlying [`proc_macro::Span::join`] method is nightly-only. When
//! called from within a procedural macro in a nightly compiler, `Spanned` will
//! use `join` to produce the intended span. When not using a nightly compiler,
//! only the span of the *first token* of the syntax tree node is returned.
//!
//! In the common case of wanting to use the joined span as the span of a
//! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is
//! able to span the error correctly under the complete syntax tree node without
//! needing the unstable `join`.
//!
//! [`syn::Error::new_spanned`]: crate::Error::new_spanned

use proc_macro2::Span;
use quote::spanned::Spanned as ToTokens;

/// A trait that can provide the `Span` of the complete contents of a syntax
/// tree node.
///
/// This trait is automatically implemented for all types that implement
/// [`ToTokens`] from the `quote` crate, as well as for `Span` itself.
///
/// [`ToTokens`]: quote::ToTokens
///
/// See the [module documentation] for an example.
///
/// [module documentation]: self
///
/// *This trait is available if Syn is built with both the `"parsing"` and
/// `"printing"` features.*
pub trait Spanned {
    /// Returns a `Span` covering the complete contents of this syntax tree
    /// node, or [`Span::call_site()`] if this node is empty.
    ///
    /// [`Span::call_site()`]: proc_macro2::Span::call_site
    fn span(&self) -> Span;
}

impl<T: ?Sized + ToTokens> Spanned for T {
    fn span(&self) -> Span {
        self.__span()
    }
}
<|endoftext|>


<commit_before>//! Tape is a representation of the Turing machine infinite tape.

pub trait Tape<S: Clone> {
    /// Reads the symbol at the location of the head of the Turing machine
    fn read(&self) -> S;

    // Writes symbol at the location of the head of the Turing machine
    fn write(&self, symbol: S) -> Self;

    // The blank symbol for this tape
    fn blank(&self) -> S;

    // Move the head of the Turing machine to the left on this tape
    fn left(&self) -> Self;

    // Move the head of the Turing machine to the right on this tape
    fn right(&self) -> Self;
}

#[derive(Clone)]
pub struct ConcreteTape<S: Clone> {
    blank: S,
    left: HalfTape<S>,
    current: S,
    right: HalfTape<S>,
}

#[derive(Clone)]
enum HalfTape<S: Clone> {
    Cell(S, Box<HalfTape<S>>),
    Empty,
}

impl<S: Clone> HalfTape<S> {
    fn empty() -> HalfTape<S> {
        HalfTape::Empty
    }

    fn pop(&self) -> (Option<S>, HalfTape<S>) {
        match *self {
            HalfTape::Cell(ref symbol, ref boxed_tail) => {
                (Some(symbol.clone()), *boxed_tail.clone())
            },
            HalfTape::Empty => (None, HalfTape::Empty)
        }
    }

    fn push(self, symbol: S) -> HalfTape<S> {
        HalfTape::Cell(symbol, Box::new(self))
    }
}

impl<S:Clone> ConcreteTape<S> {
    pub fn empty(blank: S) -> ConcreteTape<S> {
        ConcreteTape {
            blank: blank.clone(),
            left: HalfTape::empty(),
            current: blank.clone(),
            right: HalfTape::empty()
        }
    }
}

impl<S: Clone> Tape<S> for ConcreteTape<S> {
    fn read(&self) -> S {
        self.current.clone()
    }

    fn write(&self, symbol: S) -> ConcreteTape<S> {
        ConcreteTape {
            current: symbol, .. self.clone()
        }
    }

    fn blank(&self) -> S {
        self.blank.clone()
    }

    fn left(&self) -> ConcreteTape<S> {
        let (option, left_tail) = self.left.pop();
        match option {
            Some(symbol) => ConcreteTape {
                left: left_tail,
                current: symbol,
                right: self.right.clone().push(self.current.clone()),
                .. self.clone()
            },
            None => ConcreteTape {
                left: left_tail,
                current: self.blank(),
                right: self.right.clone().push(self.current.clone()),
                .. self.clone()
            }
        }
    }

    fn right(&self) -> ConcreteTape<S> {
        let (option, right_tail) = self.right.pop();
        match option {
            Some(symbol) => ConcreteTape {
                left: self.right.clone().push(self.current.clone()),
                current: symbol,
                right: right_tail,
                .. self.clone()
            },
            None => ConcreteTape {
                left: self.left.clone().push(self.current.clone()),
                current: self.blank(),
                right: right_tail,
                .. self.clone()
            }
        }
    }
}

pub struct TapeBuilder<S: Clone> {
    tape : ConcreteTape<S>,
}

impl<S: Clone> TapeBuilder<S> {
    pub fn with_blank(blank: S) -> TapeBuilder<S> {
        TapeBuilder { tape: ConcreteTape::empty(blank) }
    }

    pub fn with_current(&self, symbol: S) -> TapeBuilder<S> {
        TapeBuilder { tape: self.tape.write(symbol) }
    }

    pub fn with_right_tape(&self, mut symbols: Vec<S>) -> TapeBuilder<S> {
        symbols.reverse();

        let mut half_tape: HalfTape<S> = HalfTape::empty();
        for symbol in symbols {
            half_tape = half_tape.push(symbol)
        }

        TapeBuilder {
            tape: ConcreteTape {
                right: half_tape,
                .. self.tape.clone()
            }
        }
    }

    pub fn with_left_tape(&self, mut symbols: Vec<S>) -> TapeBuilder<S> {
        symbols.reverse();

        let mut half_tape: HalfTape<S> = HalfTape::empty();
        for symbol in symbols {
            half_tape = half_tape.push(symbol)
        }

        TapeBuilder {
            tape: ConcreteTape {
                left: half_tape,
                .. self.tape.clone()
            }
        }
    }

    pub fn build(&self) -> ConcreteTape<S> {
        self.tape.clone()
    }
}

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

    #[test]
    fn empty_tape_should_read_head() {
        let t = ConcreteTape::empty("_");

        let symbol = t.read();

        assert_eq!(symbol, t.blank());
    }

    #[test]
    fn empty_tape_should_introduce_blanks_when_moved_left() {
        let mut t = ConcreteTape::empty("_");
        t = t.left();

        let symbol = t.read();

        assert_eq!(symbol, t.blank());
    }

    #[test]
    fn empty_tape_should_introduce_blanks_when_moved_right() {
        let mut t = ConcreteTape::empty("_");
        t = t.right();

        let symbol = t.read();

        assert_eq!(symbol, t.blank());
    }

    #[test]
    fn tape_should_be_loaded_with_initial_symbols_on_the_right() {
        let mut t = TapeBuilder::with_blank("_")
            .with_current("a")
            .with_right_tape(vec!["b", "c", "d"])
            .build();

        let mut symbol = t.read();
        assert_eq!(symbol, "a");

        t = t.right();
        symbol = t.read();
        assert_eq!(symbol, "b");
    }

    #[test]
    fn tape_should_be_loaded_with_initial_symbols_on_the_left() {
        let mut t = TapeBuilder::with_blank("_")
            .with_current("a")
            .with_left_tape(vec!["b", "c", "d"])
            .build();

        let mut symbol = t.read();
        assert_eq!(symbol, "a");

        t = t.left();
        symbol = t.read();
        assert_eq!(symbol, "b");
    }
}
<commit_msg>Describe what you can do with the tape<commit_after>//! Tape is a representation of the Turing machine infinite tape.
//!
//! You can read from it, write to it and move it left and right.

pub trait Tape<S: Clone> {
    /// Reads the symbol at the location of the head of the Turing machine
    fn read(&self) -> S;

    // Writes symbol at the location of the head of the Turing machine
    fn write(&self, symbol: S) -> Self;

    // The blank symbol for this tape
    fn blank(&self) -> S;

    // Move the head of the Turing machine to the left on this tape
    fn left(&self) -> Self;

    // Move the head of the Turing machine to the right on this tape
    fn right(&self) -> Self;
}

#[derive(Clone)]
pub struct ConcreteTape<S: Clone> {
    blank: S,
    left: HalfTape<S>,
    current: S,
    right: HalfTape<S>,
}

#[derive(Clone)]
enum HalfTape<S: Clone> {
    Cell(S, Box<HalfTape<S>>),
    Empty,
}

impl<S: Clone> HalfTape<S> {
    fn empty() -> HalfTape<S> {
        HalfTape::Empty
    }

    fn pop(&self) -> (Option<S>, HalfTape<S>) {
        match *self {
            HalfTape::Cell(ref symbol, ref boxed_tail) => {
                (Some(symbol.clone()), *boxed_tail.clone())
            },
            HalfTape::Empty => (None, HalfTape::Empty)
        }
    }

    fn push(self, symbol: S) -> HalfTape<S> {
        HalfTape::Cell(symbol, Box::new(self))
    }
}

impl<S:Clone> ConcreteTape<S> {
    pub fn empty(blank: S) -> ConcreteTape<S> {
        ConcreteTape {
            blank: blank.clone(),
            left: HalfTape::empty(),
            current: blank.clone(),
            right: HalfTape::empty()
        }
    }
}

impl<S: Clone> Tape<S> for ConcreteTape<S> {
    fn read(&self) -> S {
        self.current.clone()
    }

    fn write(&self, symbol: S) -> ConcreteTape<S> {
        ConcreteTape {
            current: symbol, .. self.clone()
        }
    }

    fn blank(&self) -> S {
        self.blank.clone()
    }

    fn left(&self) -> ConcreteTape<S> {
        let (option, left_tail) = self.left.pop();
        match option {
            Some(symbol) => ConcreteTape {
                left: left_tail,
                current: symbol,
                right: self.right.clone().push(self.current.clone()),
                .. self.clone()
            },
            None => ConcreteTape {
                left: left_tail,
                current: self.blank(),
                right: self.right.clone().push(self.current.clone()),
                .. self.clone()
            }
        }
    }

    fn right(&self) -> ConcreteTape<S> {
        let (option, right_tail) = self.right.pop();
        match option {
            Some(symbol) => ConcreteTape {
                left: self.right.clone().push(self.current.clone()),
                current: symbol,
                right: right_tail,
                .. self.clone()
            },
            None => ConcreteTape {
                left: self.left.clone().push(self.current.clone()),
                current: self.blank(),
                right: right_tail,
                .. self.clone()
            }
        }
    }
}

pub struct TapeBuilder<S: Clone> {
    tape : ConcreteTape<S>,
}

impl<S: Clone> TapeBuilder<S> {
    pub fn with_blank(blank: S) -> TapeBuilder<S> {
        TapeBuilder { tape: ConcreteTape::empty(blank) }
    }

    pub fn with_current(&self, symbol: S) -> TapeBuilder<S> {
        TapeBuilder { tape: self.tape.write(symbol) }
    }

    pub fn with_right_tape(&self, mut symbols: Vec<S>) -> TapeBuilder<S> {
        symbols.reverse();

        let mut half_tape: HalfTape<S> = HalfTape::empty();
        for symbol in symbols {
            half_tape = half_tape.push(symbol)
        }

        TapeBuilder {
            tape: ConcreteTape {
                right: half_tape,
                .. self.tape.clone()
            }
        }
    }

    pub fn with_left_tape(&self, mut symbols: Vec<S>) -> TapeBuilder<S> {
        symbols.reverse();

        let mut half_tape: HalfTape<S> = HalfTape::empty();
        for symbol in symbols {
            half_tape = half_tape.push(symbol)
        }

        TapeBuilder {
            tape: ConcreteTape {
                left: half_tape,
                .. self.tape.clone()
            }
        }
    }

    pub fn build(&self) -> ConcreteTape<S> {
        self.tape.clone()
    }
}

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

    #[test]
    fn empty_tape_should_read_head() {
        let t = ConcreteTape::empty("_");

        let symbol = t.read();

        assert_eq!(symbol, t.blank());
    }

    #[test]
    fn empty_tape_should_introduce_blanks_when_moved_left() {
        let mut t = ConcreteTape::empty("_");
        t = t.left();

        let symbol = t.read();

        assert_eq!(symbol, t.blank());
    }

    #[test]
    fn empty_tape_should_introduce_blanks_when_moved_right() {
        let mut t = ConcreteTape::empty("_");
        t = t.right();

        let symbol = t.read();

        assert_eq!(symbol, t.blank());
    }

    #[test]
    fn tape_should_be_loaded_with_initial_symbols_on_the_right() {
        let mut t = TapeBuilder::with_blank("_")
            .with_current("a")
            .with_right_tape(vec!["b", "c", "d"])
            .build();

        let mut symbol = t.read();
        assert_eq!(symbol, "a");

        t = t.right();
        symbol = t.read();
        assert_eq!(symbol, "b");
    }

    #[test]
    fn tape_should_be_loaded_with_initial_symbols_on_the_left() {
        let mut t = TapeBuilder::with_blank("_")
            .with_current("a")
            .with_left_tape(vec!["b", "c", "d"])
            .build();

        let mut symbol = t.read();
        assert_eq!(symbol, "a");

        t = t.left();
        symbol = t.read();
        assert_eq!(symbol, "b");
    }
}
<|endoftext|>


<commit_before>extern crate tempdir;

use std::env;
use std::fs::{self, File, OpenOptions};
use std::process::Command;
use std::io::Write;

use tempdir::TempDir;

macro_rules! try {
    ($e:expr) => {
        $e.unwrap_or_else(|e| panic!("{} with {}", stringify!($e), e))
    }
}

const CRATES: &'static [&'static str] = &["alloc", "collections", "core", "rand", "rustc_unicode"];
const LIB_RS: &'static [u8] = b"#![no_std]";

const CUSTOM_JSON: &'static str = r#"
    {
      "arch": "arm",
      "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
      "llvm-target": "thumbv7m-none-eabi",
      "os": "none",
      "target-endian": "little",
      "target-pointer-width": "32"
    }
"#;

const NO_ATOMICS_JSON: &'static str = r#"
    {
      "arch": "arm",
      "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
      "llvm-target": "thumbv6m-none-eabi",
      "max-atomic-width": 0,
      "os": "none",
      "target-endian": "little",
      "target-pointer-width": "32"
    }
"#;

fn xargo() -> Command {
    let mut path = try!(env::current_exe());
    path.pop();
    path.push("xargo");
    Command::new(path)
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    let output = try!(cmd.output());
    if !output.status.success() {
        println!("--- stdout:\n{}", String::from_utf8_lossy(&output.stdout));
        println!("--- stderr:\n{}", String::from_utf8_lossy(&output.stderr));
        panic!("expected success, got: {}", output.status);
    }
}

fn exists_rlib(krate: &str, target: &str) -> bool {
    let home = env::home_dir().unwrap();

    for entry in try!(fs::read_dir(home.join(format!(".xargo/lib/rustlib/{}/lib", target)))) {
        let path = &try!(entry).path();

        if path.is_file() && path.extension().and_then(|e| e.to_str()) == Some("rlib") &&
           path.file_stem()
            .and_then(|f| f.to_str())
            .map(|s| s.starts_with(&format!("lib{}", krate))) == Some(true) {
            return true;
        }
    }

    false
}

fn cleanup(target: &str) {
    try!(fs::remove_dir_all(env::home_dir()
        .unwrap()
        .join(format!(".xargo/lib/rustlib/{}", target))));
}

#[test]
fn simple() {
    const TARGET: &'static str = "__simple";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

// Calling `xargo build` twice shouldn't trigger a sysroot rebuild
// The only case the sysroot would have to be rebuild is when the source is updated but that
// shouldn't happen when running this test suite.
#[test]
fn twice() {
    const TARGET: &'static str = "__twice";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    let output = try!(xargo().args(&["build", "--target", TARGET]).current_dir(td).output());

    assert!(output.status.success());

    assert!(try!(String::from_utf8(output.stderr)).lines().all(|l| !l.contains("Compiling")));

    cleanup(TARGET);
}

// Check that `xargo build` builds a sysroot for the default target in .cargo/config
#[test]
fn cargo_config() {
    const CONFIG: &'static str = "[build]\ntarget = '{}'";
    const TARGET: &'static str = "__cargo_config";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    try!(fs::create_dir(td.join(".cargo")));
    try!(try!(File::create(td.join(".cargo/config")))
        .write_all(CONFIG.replace("{}", TARGET).as_bytes()));
    run(xargo().arg("build").current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

// Check that `--targer foo` overrides the default target in .cargo/config
#[test]
fn override_cargo_config() {
    const CONFIG: &'static [u8] = b"[build]\ntarget = 'dummy'";
    const TARGET: &'static str = "__override_cargo_config";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    try!(fs::create_dir(td.join(".cargo")));
    try!(try!(File::create(td.join(".cargo/config"))).write_all(CONFIG));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

// Check that the rustflags in .cargo/config are used to build the sysroot
#[test]
fn rustflags_in_cargo_config() {
    const TARGET: &'static str = "__rustflags_in_cargo_config";
    const CARGO_CONFIG: &'static str = "[build]\nrustflags = ['--cfg', 'xargo']";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));
    try!(fs::create_dir(td.join(".cargo")));
    try!(try!(File::create(td.join(".cargo/config"))).write_all(CARGO_CONFIG.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    let output = try!(xargo()
        .args(&["build", "--target", TARGET, "--verbose"])
        .current_dir(td)
        .output());

    assert!(output.status.success());

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    let mut at_least_once = false;
    for line in try!(String::from_utf8(output.stderr)).lines() {
        if line.contains("Running") && line.contains("rustc") && line.contains(TARGET) {
            at_least_once = true;
            assert!(line.contains("--cfg xargo"));
        }
    }

    assert!(at_least_once);

    cleanup(TARGET);
}

// Check that the sysroot is rebuilt when RUSTFLAGS is modified
#[test]
fn rebuild_on_modified_rustflags() {
    const TARGET: &'static str = "__rebuild_on_modified_rustflags";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo()
        .args(&["build", "--target", TARGET, "--verbose"])
        .current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    let output = try!(xargo()
        .args(&["build", "--target", TARGET])
        .current_dir(td)
        .env("RUSTFLAGS", "--cfg xargo")
        .output());

    assert!(output.status.success());

    let stderr = try!(String::from_utf8(output.stderr));

    for krate in CRATES {
        assert!(stderr.lines()
            .any(|l| l.contains("Compiling") && l.contains(krate)));
        assert!(exists_rlib(krate, TARGET));
    }

    // Another call with the same RUSTFLAGS shouldn't trigger a rebuild
    let output = try!(xargo()
        .args(&["build", "--target", TARGET])
        .current_dir(td)
        .env("RUSTFLAGS", "--cfg xargo")
        .output());

    assert!(output.status.success());

    let stderr = try!(String::from_utf8(output.stderr));

    assert!(stderr.lines().all(|l| !l.contains("Compiling")));

    cleanup(TARGET);
}

// For targets that don't support atomics, Xargo only compiles the `core` crate
#[test]
fn no_atomics() {
    const TARGET: &'static str = "__no_atomics";
    const CRATES: &'static [&'static str] = &["core", "rustc_unicode"];

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET))))
        .write_all(NO_ATOMICS_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

#[test]
fn panic_abort() {
    const TARGET: &'static str = "__panic_abort";
    const PROFILES: &'static [u8] = b"
[profile.dev]
panic = \"abort\"

[profile.release]
panic = \"abort\"
";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    try!(try!(OpenOptions::new().append(true).write(true).open(td.join("Cargo.toml")))
        .write_all(PROFILES));

    let output =
        try!(xargo().args(&["build", "--target", TARGET, "--verbose"]).current_dir(td).output());

    assert!(output.status.success());

    let stderr = try!(String::from_utf8(output.stderr));

    let mut at_least_once = false;
    for line in stderr.lines() {
        if line.contains("Running") && line.contains("rustc") && line.contains(TARGET) {
            at_least_once = true;

            if !line.contains("-C panic=abort") {
                panic!("{}", line);
            }
            // assert!(line.contains("-C panic=abort"));
        }
    }

    assert!(at_least_once);

    cleanup(TARGET);
}
<commit_msg>smoke test 'xargo doc'<commit_after>extern crate tempdir;

use std::env;
use std::fs::{self, File, OpenOptions};
use std::process::Command;
use std::io::Write;

use tempdir::TempDir;

macro_rules! try {
    ($e:expr) => {
        $e.unwrap_or_else(|e| panic!("{} with {}", stringify!($e), e))
    }
}

const CRATES: &'static [&'static str] = &["alloc", "collections", "core", "rand", "rustc_unicode"];
const LIB_RS: &'static [u8] = b"#![no_std]";

const CUSTOM_JSON: &'static str = r#"
    {
      "arch": "arm",
      "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
      "llvm-target": "thumbv7m-none-eabi",
      "os": "none",
      "target-endian": "little",
      "target-pointer-width": "32"
    }
"#;

const NO_ATOMICS_JSON: &'static str = r#"
    {
      "arch": "arm",
      "data-layout": "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64",
      "llvm-target": "thumbv6m-none-eabi",
      "max-atomic-width": 0,
      "os": "none",
      "target-endian": "little",
      "target-pointer-width": "32"
    }
"#;

fn xargo() -> Command {
    let mut path = try!(env::current_exe());
    path.pop();
    path.push("xargo");
    Command::new(path)
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    let output = try!(cmd.output());
    if !output.status.success() {
        println!("--- stdout:\n{}", String::from_utf8_lossy(&output.stdout));
        println!("--- stderr:\n{}", String::from_utf8_lossy(&output.stderr));
        panic!("expected success, got: {}", output.status);
    }
}

fn exists_rlib(krate: &str, target: &str) -> bool {
    let home = env::home_dir().unwrap();

    for entry in try!(fs::read_dir(home.join(format!(".xargo/lib/rustlib/{}/lib", target)))) {
        let path = &try!(entry).path();

        if path.is_file() && path.extension().and_then(|e| e.to_str()) == Some("rlib") &&
           path.file_stem()
            .and_then(|f| f.to_str())
            .map(|s| s.starts_with(&format!("lib{}", krate))) == Some(true) {
            return true;
        }
    }

    false
}

fn cleanup(target: &str) {
    try!(fs::remove_dir_all(env::home_dir()
        .unwrap()
        .join(format!(".xargo/lib/rustlib/{}", target))));
}

#[test]
fn simple() {
    const TARGET: &'static str = "__simple";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

#[test]
fn doc() {
    const TARGET: &'static str = "__doc";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
         .write_all(LIB_RS));
    run(xargo().args(&["doc", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

// Calling `xargo build` twice shouldn't trigger a sysroot rebuild
// The only case the sysroot would have to be rebuild is when the source is updated but that
// shouldn't happen when running this test suite.
#[test]
fn twice() {
    const TARGET: &'static str = "__twice";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    let output = try!(xargo().args(&["build", "--target", TARGET]).current_dir(td).output());

    assert!(output.status.success());

    assert!(try!(String::from_utf8(output.stderr)).lines().all(|l| !l.contains("Compiling")));

    cleanup(TARGET);
}

// Check that `xargo build` builds a sysroot for the default target in .cargo/config
#[test]
fn cargo_config() {
    const CONFIG: &'static str = "[build]\ntarget = '{}'";
    const TARGET: &'static str = "__cargo_config";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    try!(fs::create_dir(td.join(".cargo")));
    try!(try!(File::create(td.join(".cargo/config")))
        .write_all(CONFIG.replace("{}", TARGET).as_bytes()));
    run(xargo().arg("build").current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

// Check that `--targer foo` overrides the default target in .cargo/config
#[test]
fn override_cargo_config() {
    const CONFIG: &'static [u8] = b"[build]\ntarget = 'dummy'";
    const TARGET: &'static str = "__override_cargo_config";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    try!(fs::create_dir(td.join(".cargo")));
    try!(try!(File::create(td.join(".cargo/config"))).write_all(CONFIG));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

// Check that the rustflags in .cargo/config are used to build the sysroot
#[test]
fn rustflags_in_cargo_config() {
    const TARGET: &'static str = "__rustflags_in_cargo_config";
    const CARGO_CONFIG: &'static str = "[build]\nrustflags = ['--cfg', 'xargo']";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));
    try!(fs::create_dir(td.join(".cargo")));
    try!(try!(File::create(td.join(".cargo/config"))).write_all(CARGO_CONFIG.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    let output = try!(xargo()
        .args(&["build", "--target", TARGET, "--verbose"])
        .current_dir(td)
        .output());

    assert!(output.status.success());

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    let mut at_least_once = false;
    for line in try!(String::from_utf8(output.stderr)).lines() {
        if line.contains("Running") && line.contains("rustc") && line.contains(TARGET) {
            at_least_once = true;
            assert!(line.contains("--cfg xargo"));
        }
    }

    assert!(at_least_once);

    cleanup(TARGET);
}

// Check that the sysroot is rebuilt when RUSTFLAGS is modified
#[test]
fn rebuild_on_modified_rustflags() {
    const TARGET: &'static str = "__rebuild_on_modified_rustflags";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo()
        .args(&["build", "--target", TARGET, "--verbose"])
        .current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    let output = try!(xargo()
        .args(&["build", "--target", TARGET])
        .current_dir(td)
        .env("RUSTFLAGS", "--cfg xargo")
        .output());

    assert!(output.status.success());

    let stderr = try!(String::from_utf8(output.stderr));

    for krate in CRATES {
        assert!(stderr.lines()
            .any(|l| l.contains("Compiling") && l.contains(krate)));
        assert!(exists_rlib(krate, TARGET));
    }

    // Another call with the same RUSTFLAGS shouldn't trigger a rebuild
    let output = try!(xargo()
        .args(&["build", "--target", TARGET])
        .current_dir(td)
        .env("RUSTFLAGS", "--cfg xargo")
        .output());

    assert!(output.status.success());

    let stderr = try!(String::from_utf8(output.stderr));

    assert!(stderr.lines().all(|l| !l.contains("Compiling")));

    cleanup(TARGET);
}

// For targets that don't support atomics, Xargo only compiles the `core` crate
#[test]
fn no_atomics() {
    const TARGET: &'static str = "__no_atomics";
    const CRATES: &'static [&'static str] = &["core", "rustc_unicode"];

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET))))
        .write_all(NO_ATOMICS_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    run(xargo().args(&["build", "--target", TARGET]).current_dir(td));

    for krate in CRATES {
        assert!(exists_rlib(krate, TARGET));
    }

    cleanup(TARGET);
}

#[test]
fn panic_abort() {
    const TARGET: &'static str = "__panic_abort";
    const PROFILES: &'static [u8] = b"
[profile.dev]
panic = \"abort\"

[profile.release]
panic = \"abort\"
";

    let td = try!(TempDir::new("xargo"));
    let td = &td.path();
    try!(try!(File::create(td.join(format!("{}.json", TARGET)))).write_all(CUSTOM_JSON.as_bytes()));

    run(xargo().args(&["init", "--vcs", "none", "--name", TARGET]).current_dir(td));
    try!(try!(OpenOptions::new().truncate(true).write(true).open(td.join("src/lib.rs")))
        .write_all(LIB_RS));
    try!(try!(OpenOptions::new().append(true).write(true).open(td.join("Cargo.toml")))
        .write_all(PROFILES));

    let output =
        try!(xargo().args(&["build", "--target", TARGET, "--verbose"]).current_dir(td).output());

    assert!(output.status.success());

    let stderr = try!(String::from_utf8(output.stderr));

    let mut at_least_once = false;
    for line in stderr.lines() {
        if line.contains("Running") && line.contains("rustc") && line.contains(TARGET) {
            at_least_once = true;

            if !line.contains("-C panic=abort") {
                panic!("{}", line);
            }
            // assert!(line.contains("-C panic=abort"));
        }
    }

    assert!(at_least_once);

    cleanup(TARGET);
}
<|endoftext|>


<commit_before>#![feature(core)]

extern crate deuterium;
extern crate time;

use deuterium::*;

#[macro_export]
macro_rules! assert_sql {
    ($query:expr, $s:expr) => (
        assert_eq!($query.to_final_sql(&mut SqlContext::new(box sql::PostgreSqlAdapter)).as_slice(), $s)
    )
}

mod select;
mod where_;
// mod order;
// mod join;
// mod group_by;
// mod insert;
// mod update;
// mod delete;
// mod placeholder;

#[test]
fn select_order() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query: SelectQuery<(String), LimitOne, ()> = jedi_table.select_1(&name)
        .first().order_by(&name);

    assert_sql!(query, "SELECT name FROM jedi ORDER BY name ASC LIMIT 1;");

}

#[test]
fn select_left_join() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().left_join(&jedi_table.alias("j"), name.is(name.clone()));
    assert_sql!(query, "SELECT * FROM jedi LEFT JOIN jedi AS j ON name = name;");

}<commit_msg>refactor(lib): refactor join and order tests<commit_after>#![feature(core)]

extern crate deuterium;
extern crate time;

use deuterium::*;

#[macro_export]
macro_rules! assert_sql {
    ($query:expr, $s:expr) => (
        assert_eq!($query.to_final_sql(&mut SqlContext::new(box sql::PostgreSqlAdapter)).as_slice(), $s)
    )
}

mod select;
mod where_;
mod order;
mod join;
// mod group_by;
// mod insert;
// mod update;
// mod delete;
// mod placeholder;

#[test]
fn select_order() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query: SelectQuery<(String), LimitOne, ()> = jedi_table.select_1(&name)
        .first().order_by(&name);

    assert_sql!(query, "SELECT name FROM jedi ORDER BY name ASC LIMIT 1;");

}

#[test]
fn select_left_join() {

    let jedi_table = TableDef::new("jedi");
    let name = NamedField::<String>::field_of("name", &jedi_table);

    let query = jedi_table.select_all().left_join(&jedi_table.alias("j"), name.is(name.clone()));
    assert_sql!(query, "SELECT * FROM jedi LEFT JOIN jedi AS j ON name = name;");

}<|endoftext|>