<commit_before>mod builder;
mod shutdown;
mod task_executor;

#[cfg(feature = "async-await-preview")]
mod async_await;

pub use self::builder::Builder;
pub use self::shutdown::Shutdown;
pub use self::task_executor::TaskExecutor;

use crate::reactor::{Handle, Reactor};
use futures;
use futures::future::Future;
use tokio_executor::enter;
use tokio_threadpool as threadpool;
use std::io;
use std::sync::Mutex;

/// Handle to the Tokio runtime.
///
/// The Tokio runtime includes a reactor as well as an executor for running
/// tasks.
///
/// Instances of `Runtime` can be created using [`new`] or [`Builder`]. However,
/// most users will use [`tokio::run`], which uses a `Runtime` internally.
///
/// See [module level][mod] documentation for more details.
///
/// [mod]: index.html
/// [`new`]: #method.new
/// [`Builder`]: struct.Builder.html
/// [`tokio::run`]: fn.run.html
#[derive(Debug)]
pub struct Runtime {
    inner: Option<Inner>,
}

#[derive(Debug)]
struct Inner {
    /// A handle to the reactor in the background thread.
    reactor_handle: Handle,

    // TODO: This should go away in 0.2
    reactor: Mutex<Option<Reactor>>,

    /// Task execution pool.
    pool: threadpool::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
/// # use futures::{Future, Stream};
/// use tokio::net::TcpListener;
///
/// # fn process<T>(_: T) -> Box<dyn 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,
{
    // Check enter before creating a new Runtime...
    let mut entered = enter().expect("nested tokio::run");
    let mut runtime = Runtime::new().expect("failed to start new Runtime");
    runtime.spawn(future);
    entered
        .block_on(runtime.shutdown_on_idle())
        .expect("shutdown cannot error")
}

impl Runtime {
    /// Create a new runtime instance with default configuration values.
    ///
    /// This results in a reactor, thread pool, and timer being initialized. The
    /// thread pool will not spawn any worker threads until it needs to, i.e.
    /// tasks are scheduled to run.
    ///
    /// Most users will not need to call this function directly, instead they
    /// will use [`tokio::run`](fn.run.html).
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// # Examples
    ///
    /// Creating a new `Runtime` with default configuration values.
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// use tokio::prelude::*;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    ///
    /// // Shutdown the runtime
    /// rt.shutdown_now()
    ///     .wait().unwrap();
    /// ```
    ///
    /// [mod]: index.html
    pub fn new() -> io::Result<Self> {
        Builder::new().build()
    }

    #[deprecated(since = "0.1.5", note = "use `reactor` instead")]
    #[doc(hidden)]
    pub fn handle(&self) -> &Handle {
        #[allow(deprecated)]
        self.reactor()
    }

    /// Return a reference to the reactor handle for this runtime instance.
    ///
    /// The returned handle reference can be cloned in order to get an owned
    /// value of the handle. This handle can be used to initialize I/O resources
    /// (like TCP or UDP sockets) that will not be used on the runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// let reactor_handle = rt.reactor().clone();
    ///
    /// // use `reactor_handle`
    /// ```
    #[deprecated(since = "0.1.11", note = "there is now a reactor per worker thread")]
    pub fn reactor(&self) -> &Handle {
        let mut reactor = self.inner().reactor.lock().unwrap();
        if let Some(reactor) = reactor.take() {
            if let Ok(background) = reactor.background() {
                background.forget();
            }
        }

        &self.inner().reactor_handle
    }

    /// Return a handle to the runtime's executor.
    ///
    /// The returned handle can be used to spawn tasks that run on this runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// let executor_handle = rt.executor();
    ///
    /// // use `executor_handle`
    /// ```
    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
    /// # 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
    }

    /// Run a future to completion on the Tokio runtime.
    ///
    /// This runs the given future on the runtime, blocking until it is
    /// complete, and yielding its resolved result. Any tasks or timers which
    /// the future spawns internally will be executed on the runtime.
    ///
    /// This method should not be called from an asynchronous context.
    ///
    /// # Panics
    ///
    /// This function panics if the executor is at capacity, if the provided
    /// future panics, or if called within an asynchronous execution context.
    pub fn block_on<F, R, E>(&mut self, future: F) -> Result<R, E>
    where
        F: Send + 'static + Future<Item = R, Error = E>,
        R: Send + 'static,
        E: Send + 'static,
    {
        let mut entered = enter().expect("nested block_on");
        let (tx, rx) = futures::sync::oneshot::channel();
        self.spawn(future.then(move |r| tx.send(r).map_err(|_| unreachable!())));
        entered.block_on(rx).unwrap()
    }

    /// Run a future to completion on the Tokio runtime, then wait for all
    /// background futures to complete too.
    ///
    /// This runs the given future on the runtime, blocking until it is
    /// complete, waiting for background futures to complete, and yielding
    /// its resolved result. Any tasks or timers which the future spawns
    /// internally will be executed on the runtime and waited for completion.
    ///
    /// This method should not be called from an asynchronous context.
    ///
    /// # Panics
    ///
    /// This function panics if the executor is at capacity, if the provided
    /// future panics, or if called within an asynchronous execution context.
    pub fn block_on_all<F, R, E>(mut self, future: F) -> Result<R, E>
    where
        F: Send + 'static + Future<Item = R, Error = E>,
        R: Send + 'static,
        E: Send + 'static,
    {
        let mut entered = enter().expect("nested block_on_all");
        let (tx, rx) = futures::sync::oneshot::channel();
        self.spawn(future.then(move |r| tx.send(r).map_err(|_| unreachable!())));
        let block = rx
            .map_err(|_| unreachable!())
            .and_then(move |r| {
                self.shutdown_on_idle()
                    .map(move |()| r)
            });
        entered.block_on(block).unwrap()
    }

    /// 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.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// use tokio::prelude::*;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    ///
    /// // Shutdown the runtime
    /// rt.shutdown_on_idle()
    ///     .wait().unwrap();
    /// ```
    ///
    /// [mod]: index.html
    pub fn shutdown_on_idle(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();
        let inner = inner.pool.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.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// use tokio::prelude::*;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    ///
    /// // Shutdown the runtime
    /// rt.shutdown_now()
    ///     .wait().unwrap();
    /// ```
    ///
    /// [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();
        }
    }
}
<commit_msg>Use ThreadPool's impl of spawn (#1139)<commit_after>mod builder;
mod shutdown;
mod task_executor;

#[cfg(feature = "async-await-preview")]
mod async_await;

pub use self::builder::Builder;
pub use self::shutdown::Shutdown;
pub use self::task_executor::TaskExecutor;

use crate::reactor::{Handle, Reactor};
use futures;
use futures::future::Future;
use tokio_executor::enter;
use tokio_threadpool as threadpool;
use std::io;
use std::sync::Mutex;

/// Handle to the Tokio runtime.
///
/// The Tokio runtime includes a reactor as well as an executor for running
/// tasks.
///
/// Instances of `Runtime` can be created using [`new`] or [`Builder`]. However,
/// most users will use [`tokio::run`], which uses a `Runtime` internally.
///
/// See [module level][mod] documentation for more details.
///
/// [mod]: index.html
/// [`new`]: #method.new
/// [`Builder`]: struct.Builder.html
/// [`tokio::run`]: fn.run.html
#[derive(Debug)]
pub struct Runtime {
    inner: Option<Inner>,
}

#[derive(Debug)]
struct Inner {
    /// A handle to the reactor in the background thread.
    reactor_handle: Handle,

    // TODO: This should go away in 0.2
    reactor: Mutex<Option<Reactor>>,

    /// Task execution pool.
    pool: threadpool::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
/// # use futures::{Future, Stream};
/// use tokio::net::TcpListener;
///
/// # fn process<T>(_: T) -> Box<dyn 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,
{
    // Check enter before creating a new Runtime...
    let mut entered = enter().expect("nested tokio::run");
    let mut runtime = Runtime::new().expect("failed to start new Runtime");
    runtime.spawn(future);
    entered
        .block_on(runtime.shutdown_on_idle())
        .expect("shutdown cannot error")
}

impl Runtime {
    /// Create a new runtime instance with default configuration values.
    ///
    /// This results in a reactor, thread pool, and timer being initialized. The
    /// thread pool will not spawn any worker threads until it needs to, i.e.
    /// tasks are scheduled to run.
    ///
    /// Most users will not need to call this function directly, instead they
    /// will use [`tokio::run`](fn.run.html).
    ///
    /// See [module level][mod] documentation for more details.
    ///
    /// # Examples
    ///
    /// Creating a new `Runtime` with default configuration values.
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// use tokio::prelude::*;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    ///
    /// // Shutdown the runtime
    /// rt.shutdown_now()
    ///     .wait().unwrap();
    /// ```
    ///
    /// [mod]: index.html
    pub fn new() -> io::Result<Self> {
        Builder::new().build()
    }

    #[deprecated(since = "0.1.5", note = "use `reactor` instead")]
    #[doc(hidden)]
    pub fn handle(&self) -> &Handle {
        #[allow(deprecated)]
        self.reactor()
    }

    /// Return a reference to the reactor handle for this runtime instance.
    ///
    /// The returned handle reference can be cloned in order to get an owned
    /// value of the handle. This handle can be used to initialize I/O resources
    /// (like TCP or UDP sockets) that will not be used on the runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// let reactor_handle = rt.reactor().clone();
    ///
    /// // use `reactor_handle`
    /// ```
    #[deprecated(since = "0.1.11", note = "there is now a reactor per worker thread")]
    pub fn reactor(&self) -> &Handle {
        let mut reactor = self.inner().reactor.lock().unwrap();
        if let Some(reactor) = reactor.take() {
            if let Ok(background) = reactor.background() {
                background.forget();
            }
        }

        &self.inner().reactor_handle
    }

    /// Return a handle to the runtime's executor.
    ///
    /// The returned handle can be used to spawn tasks that run on this runtime.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// let executor_handle = rt.executor();
    ///
    /// // use `executor_handle`
    /// ```
    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
    /// # 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.spawn(future);
        self
    }

    /// Run a future to completion on the Tokio runtime.
    ///
    /// This runs the given future on the runtime, blocking until it is
    /// complete, and yielding its resolved result. Any tasks or timers which
    /// the future spawns internally will be executed on the runtime.
    ///
    /// This method should not be called from an asynchronous context.
    ///
    /// # Panics
    ///
    /// This function panics if the executor is at capacity, if the provided
    /// future panics, or if called within an asynchronous execution context.
    pub fn block_on<F, R, E>(&mut self, future: F) -> Result<R, E>
    where
        F: Send + 'static + Future<Item = R, Error = E>,
        R: Send + 'static,
        E: Send + 'static,
    {
        let mut entered = enter().expect("nested block_on");
        let (tx, rx) = futures::sync::oneshot::channel();
        self.spawn(future.then(move |r| tx.send(r).map_err(|_| unreachable!())));
        entered.block_on(rx).unwrap()
    }

    /// Run a future to completion on the Tokio runtime, then wait for all
    /// background futures to complete too.
    ///
    /// This runs the given future on the runtime, blocking until it is
    /// complete, waiting for background futures to complete, and yielding
    /// its resolved result. Any tasks or timers which the future spawns
    /// internally will be executed on the runtime and waited for completion.
    ///
    /// This method should not be called from an asynchronous context.
    ///
    /// # Panics
    ///
    /// This function panics if the executor is at capacity, if the provided
    /// future panics, or if called within an asynchronous execution context.
    pub fn block_on_all<F, R, E>(mut self, future: F) -> Result<R, E>
    where
        F: Send + 'static + Future<Item = R, Error = E>,
        R: Send + 'static,
        E: Send + 'static,
    {
        let mut entered = enter().expect("nested block_on_all");
        let (tx, rx) = futures::sync::oneshot::channel();
        self.spawn(future.then(move |r| tx.send(r).map_err(|_| unreachable!())));
        let block = rx
            .map_err(|_| unreachable!())
            .and_then(move |r| {
                self.shutdown_on_idle()
                    .map(move |()| r)
            });
        entered.block_on(block).unwrap()
    }

    /// 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.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// use tokio::prelude::*;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    ///
    /// // Shutdown the runtime
    /// rt.shutdown_on_idle()
    ///     .wait().unwrap();
    /// ```
    ///
    /// [mod]: index.html
    pub fn shutdown_on_idle(mut self) -> Shutdown {
        let inner = self.inner.take().unwrap();
        let inner = inner.pool.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.
    ///
    /// # Examples
    ///
    /// ```
    /// use tokio::runtime::Runtime;
    /// use tokio::prelude::*;
    ///
    /// let rt = Runtime::new()
    ///     .unwrap();
    ///
    /// // Use the runtime...
    ///
    /// // Shutdown the runtime
    /// rt.shutdown_now()
    ///     .wait().unwrap();
    /// ```
    ///
    /// [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();
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

use std::convert::{TryFrom, TryInto};
use std::iter::{FromIterator, IntoIterator, Iterator};
use std::marker::PhantomData;

use crate::errors::Error;
use crate::object::{IsObjectRef, Object, ObjectPtr, ObjectRef};
use crate::{
    external,
    function::{Function, Result},
    ArgValue, RetValue,
};

#[repr(C)]
#[derive(Clone)]
pub struct Array<T: IsObjectRef> {
    object: ObjectRef,
    _data: PhantomData<T>,
}

// TODO(@jroesch): convert to use generics instead of casting inside
// the implementation.
external! {
    #[name("node.ArrayGetItem")]
    fn array_get_item(array: ObjectRef, index: isize) -> ObjectRef;
    #[name("node.ArraySize")]
    fn array_size(array: ObjectRef) -> i64;
}

impl<T: IsObjectRef> Array<T> {
    pub fn from_vec(data: Vec<T>) -> Result<Array<T>> {
        let iter = data.into_iter().map(T::into_arg_value).collect();

        let func = Function::get("node.Array").expect(
            "node.Array function is not registered, this is most likely a build or linking error",
        );

        // let array_data = func.invoke(iter)?;
        // let array_data: ObjectRef = func.invoke(iter)?.try_into()?;
        let array_data: ObjectPtr<Object> = func.invoke(iter)?.try_into()?;

        debug_assert!(
            array_data.count() >= 1,
            "array reference count is {}",
            array_data.count()
        );

        Ok(Array {
            object: array_data.into(),
            _data: PhantomData,
        })
    }

    pub fn get(&self, index: isize) -> Result<T>
    where
        T: TryFrom<RetValue, Error = Error>,
    {
        let oref: ObjectRef = array_get_item(self.object.clone(), index)?;
        oref.downcast()
    }

    pub fn len(&self) -> i64 {
        array_size(self.object.clone()).expect("size should never fail")
    }
}

impl<T: IsObjectRef> std::fmt::Debug for Array<T> {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        let as_vec: Vec<T> = self.clone().into_iter().collect();
        write!(formatter, "{:?}", as_vec)
    }
}

pub struct IntoIter<T: IsObjectRef> {
    array: Array<T>,
    pos: isize,
    size: isize,
}

impl<T: IsObjectRef> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.size {
            let item =
                self.array.get(self.pos)
                    .expect("Can not index as in-bounds position after bounds checking.\nNote: this error can only be do to an uncaught issue with API bindings.");
            self.pos += 1;
            Some(item)
        } else {
            None
        }
    }
}

impl<T: IsObjectRef> IntoIterator for Array<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        let size = self.len() as isize;
        IntoIter {
            array: self,
            pos: 0,
            size: size,
        }
    }
}

impl<T: IsObjectRef> FromIterator<T> for Array<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Array::from_vec(iter.into_iter().collect()).unwrap()
    }
}

impl<T: IsObjectRef> From<Array<T>> for ArgValue<'static> {
    fn from(array: Array<T>) -> ArgValue<'static> {
        array.object.into()
    }
}

impl<T: IsObjectRef> From<Array<T>> for RetValue {
    fn from(array: Array<T>) -> RetValue {
        array.object.into()
    }
}

impl<'a, T: IsObjectRef> TryFrom<ArgValue<'a>> for Array<T> {
    type Error = Error;

    fn try_from(array: ArgValue<'a>) -> Result<Array<T>> {
        let object_ref: ObjectRef = array.try_into()?;
        // TODO: type check
        Ok(Array {
            object: object_ref,
            _data: PhantomData,
        })
    }
}

impl<'a, T: IsObjectRef> TryFrom<RetValue> for Array<T> {
    type Error = Error;

    fn try_from(array: RetValue) -> Result<Array<T>> {
        let object_ref = array.try_into()?;
        Ok(Array {
            object: object_ref,
            _data: PhantomData,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::Array;
    use crate::function::Result;
    use crate::string::String;

    #[test]
    fn create_array_and_get() -> Result<()> {
        let vec: Vec<String> = vec!["foo".into(), "bar".into(), "baz".into()];
        let array = Array::from_vec(vec)?;
        assert_eq!(array.get(0)?.to_string(), "foo");
        assert_eq!(array.get(1)?.to_string(), "bar");
        assert_eq!(array.get(2)?.to_string(), "baz");
        Ok(())
    }
}
<commit_msg>[Rust] Impl IsObjectRef for Array (#7138)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

use std::convert::{TryFrom, TryInto};
use std::iter::{FromIterator, IntoIterator, Iterator};
use std::marker::PhantomData;

use crate::errors::Error;
use crate::object::{IsObjectRef, Object, ObjectPtr, ObjectRef};
use crate::{
    external,
    function::{Function, Result},
    ArgValue, RetValue,
};

#[repr(C)]
#[derive(Clone)]
pub struct Array<T: IsObjectRef> {
    object: ObjectRef,
    _data: PhantomData<T>,
}

// TODO(@jroesch): convert to use generics instead of casting inside
// the implementation.
external! {
    #[name("node.ArrayGetItem")]
    fn array_get_item(array: ObjectRef, index: isize) -> ObjectRef;
    #[name("node.ArraySize")]
    fn array_size(array: ObjectRef) -> i64;
}

impl<T: IsObjectRef> IsObjectRef for Array<T> {
    type Object = Object;
    fn as_ptr(&self) -> Option<&ObjectPtr<Self::Object>> {
        self.object.as_ptr()
    }
    fn into_ptr(self) -> Option<ObjectPtr<Self::Object>> {
        self.object.into_ptr()
    }
    fn from_ptr(object_ptr: Option<ObjectPtr<Self::Object>>) -> Self {
        let object_ref = match object_ptr {
            Some(o) => o.into(),
            _ => panic!(),
        };
        Array {
            object: object_ref,
            _data: PhantomData,
        }
    }
}

impl<T: IsObjectRef> Array<T> {
    pub fn from_vec(data: Vec<T>) -> Result<Array<T>> {
        let iter = data.into_iter().map(T::into_arg_value).collect();

        let func = Function::get("node.Array").expect(
            "node.Array function is not registered, this is most likely a build or linking error",
        );

        // let array_data = func.invoke(iter)?;
        // let array_data: ObjectRef = func.invoke(iter)?.try_into()?;
        let array_data: ObjectPtr<Object> = func.invoke(iter)?.try_into()?;

        debug_assert!(
            array_data.count() >= 1,
            "array reference count is {}",
            array_data.count()
        );

        Ok(Array {
            object: array_data.into(),
            _data: PhantomData,
        })
    }

    pub fn get(&self, index: isize) -> Result<T>
    where
        T: TryFrom<RetValue, Error = Error>,
    {
        let oref: ObjectRef = array_get_item(self.object.clone(), index)?;
        oref.downcast()
    }

    pub fn len(&self) -> i64 {
        array_size(self.object.clone()).expect("size should never fail")
    }
}

impl<T: IsObjectRef> std::fmt::Debug for Array<T> {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        let as_vec: Vec<T> = self.clone().into_iter().collect();
        write!(formatter, "{:?}", as_vec)
    }
}

pub struct IntoIter<T: IsObjectRef> {
    array: Array<T>,
    pos: isize,
    size: isize,
}

impl<T: IsObjectRef> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos < self.size {
            let item =
                self.array.get(self.pos)
                    .expect("Can not index as in-bounds position after bounds checking.\nNote: this error can only be do to an uncaught issue with API bindings.");
            self.pos += 1;
            Some(item)
        } else {
            None
        }
    }
}

impl<T: IsObjectRef> IntoIterator for Array<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        let size = self.len() as isize;
        IntoIter {
            array: self,
            pos: 0,
            size: size,
        }
    }
}

impl<T: IsObjectRef> FromIterator<T> for Array<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Array::from_vec(iter.into_iter().collect()).unwrap()
    }
}

impl<'a, T: IsObjectRef> From<Array<T>> for ArgValue<'a> {
    fn from(array: Array<T>) -> ArgValue<'a> {
        array.object.into()
    }
}

impl<T: IsObjectRef> From<Array<T>> for RetValue {
    fn from(array: Array<T>) -> RetValue {
        array.object.into()
    }
}

impl<'a, T: IsObjectRef> TryFrom<ArgValue<'a>> for Array<T> {
    type Error = Error;

    fn try_from(array: ArgValue<'a>) -> Result<Array<T>> {
        let object_ref: ObjectRef = array.try_into()?;
        // TODO: type check
        Ok(Array {
            object: object_ref,
            _data: PhantomData,
        })
    }
}

impl<'a, T: IsObjectRef> TryFrom<RetValue> for Array<T> {
    type Error = Error;

    fn try_from(array: RetValue) -> Result<Array<T>> {
        let object_ref = array.try_into()?;
        Ok(Array {
            object: object_ref,
            _data: PhantomData,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::Array;
    use crate::function::Result;
    use crate::object::{IsObjectRef, ObjectRef};
    use crate::string::String;

    #[test]
    fn create_array_and_get() -> Result<()> {
        let vec: Vec<String> = vec!["foo".into(), "bar".into(), "baz".into()];
        let array = Array::from_vec(vec)?;
        assert_eq!(array.get(0)?.to_string(), "foo");
        assert_eq!(array.get(1)?.to_string(), "bar");
        assert_eq!(array.get(2)?.to_string(), "baz");
        Ok(())
    }

    #[test]
    fn downcast() -> Result<()> {
        let vec: Vec<String> = vec!["foo".into(), "bar".into(), "baz".into()];
        let array: ObjectRef = ObjectRef::from_ptr(Array::from_vec(vec)?.into_ptr());
        let array: Array<ObjectRef> = array.downcast::<Array<ObjectRef>>().unwrap();
        assert_eq!(array.get(1)?.downcast::<String>().unwrap(), "bar");
        Ok(())
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed leftside edge detection<commit_after><|endoftext|>


<commit_before><commit_msg>Simplified the error type in blob index<commit_after><|endoftext|>


<commit_before><commit_msg>fix: Correct spelling on comments for "Queriables" (#43)<commit_after><|endoftext|>


<commit_before><commit_msg>Workaround for screenshot in save_screenshot being empty<commit_after><|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use data_provider::{CGDataProvider, CGDataProviderRef};

use libc;
use std::mem;

pub type CGGlyph = libc::c_ushort;

struct __CGFont;

pub type CGFontRef = *__CGFont;

pub struct CGFont {
    obj: CGFontRef,
}

impl Clone for CGFont {
    #[inline]
    fn clone(&self) -> CGFont {
        unsafe {
            TCFType::wrap_under_get_rule(self.obj)
        }
    }
}

impl Drop for CGFont {
    fn drop(&mut self) {
        unsafe {
            CFRelease(self.as_CFTypeRef())
        }
    }
}

impl TCFType<CGFontRef> for CGFont {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGFontRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGFontRef) -> CGFont {
        let reference: CGFontRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGFontRef) -> CGFont {
        CGFont {
            obj: obj,
        }
    }

    #[inline]
    fn type_id(_: Option<CGFont>) -> CFTypeID {
        unsafe {
            CGFontGetTypeID()
        }
    }
}

impl CGFont {
    pub fn from_data_provider(provider: CGDataProvider) -> CGFont {
        unsafe {
            let font_ref = CGFontCreateWithDataProvider(provider.as_concrete_TypeRef());
            TCFType::wrap_under_create_rule(font_ref)
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {

    // TODO: basically nothing has bindings (even commented-out)  besides what we use.
    fn CGFontCreateWithDataProvider(provider: CGDataProviderRef) -> CGFontRef;
    fn CGFontGetTypeID() -> CFTypeID;

    // These do the same thing as CFRetain/CFRelease, except
    // gracefully handle a NULL argument. We don't use them.
    //fn CGFontRetain(font: CGFontRef);
    //fn CGFontRelease(font: CGFontRef);
}
<commit_msg>from_data_provider now returns result indicating success.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core_foundation::base::{CFRelease, CFRetain, CFTypeID, CFTypeRef, TCFType};
use data_provider::{CGDataProvider, CGDataProviderRef};

use libc;
use std::mem;
use std::ptr;

pub type CGGlyph = libc::c_ushort;

struct __CGFont;

pub type CGFontRef = *__CGFont;

pub struct CGFont {
    obj: CGFontRef,
}

impl Clone for CGFont {
    #[inline]
    fn clone(&self) -> CGFont {
        unsafe {
            TCFType::wrap_under_get_rule(self.obj)
        }
    }
}

impl Drop for CGFont {
    fn drop(&mut self) {
        unsafe {
            let ptr = self.as_CFTypeRef();
            assert!(ptr != ptr::null());
            CFRelease(ptr);
        }
    }
}

impl TCFType<CGFontRef> for CGFont {
    #[inline]
    fn as_concrete_TypeRef(&self) -> CGFontRef {
        self.obj
    }

    #[inline]
    unsafe fn wrap_under_get_rule(reference: CGFontRef) -> CGFont {
        let reference: CGFontRef = mem::transmute(CFRetain(mem::transmute(reference)));
        TCFType::wrap_under_create_rule(reference)
    }

    #[inline]
    fn as_CFTypeRef(&self) -> CFTypeRef {
        unsafe {
            mem::transmute(self.as_concrete_TypeRef())
        }
    }

    #[inline]
    unsafe fn wrap_under_create_rule(obj: CGFontRef) -> CGFont {
        CGFont {
            obj: obj,
        }
    }

    #[inline]
    fn type_id(_: Option<CGFont>) -> CFTypeID {
        unsafe {
            CGFontGetTypeID()
        }
    }
}

impl CGFont {
    pub fn from_data_provider(provider: CGDataProvider) -> Result<CGFont, ()> {
        unsafe {
            let font_ref = CGFontCreateWithDataProvider(provider.as_concrete_TypeRef());
            if font_ref != ptr::null() {
                Ok(TCFType::wrap_under_create_rule(font_ref))
            } else {
                Err(())
            }
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
extern {

    // TODO: basically nothing has bindings (even commented-out)  besides what we use.
    fn CGFontCreateWithDataProvider(provider: CGDataProviderRef) -> CGFontRef;
    fn CGFontGetTypeID() -> CFTypeID;

    // These do the same thing as CFRetain/CFRelease, except
    // gracefully handle a NULL argument. We don't use them.
    //fn CGFontRetain(font: CGFontRef);
    //fn CGFontRelease(font: CGFontRef);
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate abomonation;
extern crate timely;
extern crate differential_dataflow;
extern crate arrayvec;

use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::time::Instant;

use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::product::Product;

use differential_dataflow::{Collection, AsCollection};

mod types;
mod queries;

use types::*;

fn main() {

    timely::execute_from_args(std::env::args().skip(4), |worker| {

        let index = worker.index();
        let peers = worker.peers();

        let prefix = ::std::env::args().nth(1).unwrap();;
        let logical_batch = ::std::env::args().nth(2).unwrap().parse::<usize>().unwrap();
        let physical_batch = ::std::env::args().nth(3).unwrap().parse::<usize>().unwrap();
        let query: usize = ::std::env::args().nth(4).unwrap().parse().unwrap();

        let (mut inputs, probes, used) = worker.dataflow::<usize,_,_>(move |scope| {

            // create new inputs to use in workers!
            let (cust_in, cust) = scope.new_input();
            let (line_in, line) = scope.new_input();
            let (nats_in, nats) = scope.new_input();
            let (ords_in, ords) = scope.new_input();
            let (part_in, part) = scope.new_input();
            let (psup_in, psup) = scope.new_input();
            let (regs_in, regs) = scope.new_input();
            let (supp_in, supp) = scope.new_input();

            let mut collections = Collections::new(
                cust.as_collection(),
                line.as_collection(),
                nats.as_collection(),
                ords.as_collection(),
                part.as_collection(),
                psup.as_collection(),
                regs.as_collection(),
                supp.as_collection(),
            );

            let mut probes = Vec::new();

            match query {
                1 => probes.push(queries::query01::query(&mut collections)),
                2 => probes.push(queries::query02::query(&mut collections)),
                3 => probes.push(queries::query03::query(&mut collections)),
                4 => probes.push(queries::query04::query(&mut collections)),
                5 => probes.push(queries::query05::query(&mut collections)),
                6 => probes.push(queries::query06::query(&mut collections)),
                7 => probes.push(queries::query07::query(&mut collections)),
                8 => probes.push(queries::query08::query(&mut collections)),
                9 => probes.push(queries::query09::query(&mut collections)),
                10 => probes.push(queries::query10::query(&mut collections)),
                11 => probes.push(queries::query11::query(&mut collections)),
                12 => probes.push(queries::query12::query(&mut collections)),
                13 => probes.push(queries::query13::query(&mut collections)),
                14 => probes.push(queries::query14::query(&mut collections)),
                15 => probes.push(queries::query15::query(&mut collections)),
                16 => probes.push(queries::query16::query(&mut collections)),
                17 => probes.push(queries::query17::query(&mut collections)),
                18 => probes.push(queries::query18::query(&mut collections)),
                19 => probes.push(queries::query19::query(&mut collections)),
                20 => probes.push(queries::query20::query(&mut collections)),
                21 => probes.push(queries::query21::query(&mut collections)),
                22 => probes.push(queries::query22::query(&mut collections)),
                _ => panic!("query: {:?} unimplemented", query),
            }

            // return the various input handles, and the list of probes.
            ((cust_in, line_in, nats_in, ords_in, part_in, psup_in, regs_in, supp_in), probes, collections.used)
        });

        // customer.tbl lineitem.tbl    nation.tbl  orders.tbl  part.tbl    partsupp.tbl    region.tbl  supplier.tbl
        let mut customers = if used[0] { load::<Customer>(prefix.as_str(), "customer.tbl", index, peers, logical_batch, physical_batch, 0) } else { Vec::new() };
        let mut lineitems = if used[1] { load::<LineItem>(prefix.as_str(), "lineitem.tbl", index, peers, logical_batch, physical_batch, 1) } else { Vec::new() };
        let mut nations = if used[2] { load::<Nation>(prefix.as_str(), "nation.tbl", index, peers, logical_batch, physical_batch, 2) } else { Vec::new() };
        let mut orders = if used[3] { load::<Order>(prefix.as_str(), "orders.tbl", index, peers, logical_batch, physical_batch, 3) } else { Vec::new() };
        let mut parts = if used[4] { load::<Part>(prefix.as_str(), "part.tbl", index, peers, logical_batch, physical_batch, 4) } else { Vec::new() };
        let mut partsupps = if used[5] { load::<PartSupp>(prefix.as_str(), "partsupp.tbl", index, peers, logical_batch, physical_batch, 5) } else { Vec::new() };
        let mut regions = if used[6] { load::<Region>(prefix.as_str(), "region.tbl", index, peers, logical_batch, physical_batch, 6) } else { Vec::new() };
        let mut suppliers = if used[7] { load::<Supplier>(prefix.as_str(), "supplier.tbl", index, peers, logical_batch, physical_batch, 7) } else { Vec::new() };

        let mut tuples = 0usize;
        tuples += customers.iter().map(|x| x.len()).sum::<usize>();
        tuples += lineitems.iter().map(|x| x.len()).sum::<usize>();
        tuples += nations.iter().map(|x| x.len()).sum::<usize>();
        tuples += orders.iter().map(|x| x.len()).sum::<usize>();
        tuples += parts.iter().map(|x| x.len()).sum::<usize>();
        tuples += partsupps.iter().map(|x| x.len()).sum::<usize>();
        tuples += regions.iter().map(|x| x.len()).sum::<usize>();
        tuples += suppliers.iter().map(|x| x.len()).sum::<usize>();

        // Synchronize before starting the timer.
        let next_round = 1;
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.advance_to(next_round);
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.advance_to(next_round);
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let timer = Instant::now();
        let mut round = 0;
        while customers.len() > 0 || lineitems.len() > 0 || nations.len() > 0 || orders.len() > 0 || parts.len() > 0 || partsupps.len() > 0 || regions.len() > 0 || suppliers.len() > 0 {

            // introduce physical batch of data for each input with remaining data.
            if let Some(mut data) = customers.pop() {
                assert!(data.iter().all(|t| inputs.0.time().le(&t.1)));
                inputs.0.send_batch(&mut data);
            }
            if let Some(mut data) = lineitems.pop() {
                for x in data.iter() {
                    if !inputs.1.time().le(&x.1) {
                        panic!("{:?} but {:?}", inputs.1.time(), &x.1);
                    }
                }
                assert!(data.iter().all(|t| inputs.1.time().le(&t.1)));
                inputs.1.send_batch(&mut data);
            }
            if let Some(mut data) = nations.pop() { inputs.2.send_batch(&mut data); }
            if let Some(mut data) = orders.pop() {
                assert!(data.iter().all(|t| inputs.3.time().le(&t.1)));
                inputs.3.send_batch(&mut data);
            }
            if let Some(mut data) = parts.pop() { inputs.4.send_batch(&mut data); }
            if let Some(mut data) = partsupps.pop() { inputs.5.send_batch(&mut data); }
            if let Some(mut data) = regions.pop() { inputs.6.send_batch(&mut data); }
            if let Some(mut data) = suppliers.pop() { inputs.7.send_batch(&mut data); }

            // catch all inputs up to the same (next) round.
            let next_round = 1 + 8 * (round + 1) * physical_batch;
            inputs.0.advance_to(next_round);
            inputs.1.advance_to(next_round);
            inputs.2.advance_to(next_round);
            inputs.3.advance_to(next_round);
            inputs.4.advance_to(next_round);
            inputs.5.advance_to(next_round);
            inputs.6.advance_to(next_round);
            inputs.7.advance_to(next_round);

            let time = inputs.0.time().clone();
            worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));
            round += 1;
        }

        // Finish outstanding work before stopping the timer.
        let next_round = usize::max_value();
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.advance_to(next_round);
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.advance_to(next_round);
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let query_name = if query < 10 { format!("q0{}", query) } else { format!("q{}", query) };
        let elapsed = timer.elapsed();
        let nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
        println!("query: {}, elapsed: {:?}, tuples: {:?}, rate: {:?}", query_name, timer.elapsed(), tuples, (tuples as f64) / (nanos as f64 / 1000000000.0));

    }).unwrap();
}

pub struct Collections<G: Scope> {
    customers: Collection<G, Customer, isize>,
    lineitems: Collection<G, LineItem, isize>,
    nations: Collection<G, Nation, isize>,
    orders: Collection<G, Order, isize>,
    parts: Collection<G, Part, isize>,
    partsupps: Collection<G, PartSupp, isize>,
    regions: Collection<G, Region, isize>,
    suppliers: Collection<G, Supplier, isize>,
    used: [bool; 8],
}

impl<G: Scope> Collections<G> {
    fn new(
        customers: Collection<G, Customer, isize>,
        lineitems: Collection<G, LineItem, isize>,
        nations: Collection<G, Nation, isize>,
        orders: Collection<G, Order, isize>,
        parts: Collection<G, Part, isize>,
        partsupps: Collection<G, PartSupp, isize>,
        regions: Collection<G, Region, isize>,
        suppliers: Collection<G, Supplier, isize>,
    ) -> Self {

        Collections {
            customers: customers,
            lineitems: lineitems,
            nations: nations,
            orders: orders,
            parts: parts,
            partsupps: partsupps,
            regions: regions,
            suppliers: suppliers,
            used: [false; 8]
        }
    }

    fn customers(&mut self) -> &Collection<G, Customer, isize> { self.used[0] = true; &self.customers }
    fn lineitems(&mut self) -> &Collection<G, LineItem, isize> { self.used[1] = true; &self.lineitems }
    fn nations(&mut self) -> &Collection<G, Nation, isize> { self.used[2] = true; &self.nations }
    fn orders(&mut self) -> &Collection<G, Order, isize> { self.used[3] = true; &self.orders }
    fn parts(&mut self) -> &Collection<G, Part, isize> { self.used[4] = true; &self.parts }
    fn partsupps(&mut self) -> &Collection<G, PartSupp, isize> { self.used[5] = true; &self.partsupps }
    fn regions(&mut self) -> &Collection<G, Region, isize> { self.used[6] = true; &self.regions }
    fn suppliers(&mut self) -> &Collection<G, Supplier, isize> { self.used[7] = true; &self.suppliers }
}

// Returns a sequence of physical batches of ready-to-go timestamped data. Not clear that `input` can exploit the pre-arrangement yet.
fn load<T>(prefix: &str, name: &str, index: usize, peers: usize, logical_batch: usize, physical_batch: usize, off: usize)
    -> Vec<Vec<(T, Product<RootTimestamp, usize>, isize)>>
where T: for<'a> From<&'a str> {

    let mut result = Vec::new();
    let mut buffer = Vec::new();

    let path = format!("{}{}", prefix, name);

    let items_file = File::open(&path).expect("didn't find items file");
    let mut items_reader =  BufReader::new(items_file);
    let mut count = 0;

    let mut line = String::new();

    while items_reader.read_line(&mut line).unwrap() > 0 {

        if count % peers == index {

            let logical = (8 * count / logical_batch) + off;
            let physical = logical / physical_batch;
            let round = physical / 8;

            while result.len() < round {
                result.push(buffer);
                buffer = Vec::with_capacity(2 + logical_batch * physical_batch / peers);
            }

            let item = T::from(line.as_str());
            buffer.push((item, RootTimestamp::new(logical + 1), 1));
        }

        count += 1;

        line.clear();
    }

    if buffer.len() > 0 {
        result.push(buffer);
    }

    result.reverse();
    result
}
<commit_msg>improved reporting<commit_after>#[macro_use]
extern crate abomonation;
extern crate timely;
extern crate differential_dataflow;
extern crate arrayvec;

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::time::Instant;

use timely::dataflow::*;
use timely::dataflow::operators::*;
use timely::progress::timestamp::RootTimestamp;
use timely::progress::nested::product::Product;

use differential_dataflow::{Collection, AsCollection};

mod types;
mod queries;

use types::*;

fn main() {

    timely::execute_from_args(std::env::args().skip(4), |worker| {

        let index = worker.index();
        let peers = worker.peers();

        let prefix = ::std::env::args().nth(1).unwrap();;
        let logical_batch = ::std::env::args().nth(2).unwrap().parse::<usize>().unwrap();
        let physical_batch = ::std::env::args().nth(3).unwrap().parse::<usize>().unwrap();
        let query: usize = ::std::env::args().nth(4).unwrap().parse().unwrap();

        let (mut inputs, probes, used) = worker.dataflow::<usize,_,_>(move |scope| {

            // create new inputs to use in workers!
            let (cust_in, cust) = scope.new_input();
            let (line_in, line) = scope.new_input();
            let (nats_in, nats) = scope.new_input();
            let (ords_in, ords) = scope.new_input();
            let (part_in, part) = scope.new_input();
            let (psup_in, psup) = scope.new_input();
            let (regs_in, regs) = scope.new_input();
            let (supp_in, supp) = scope.new_input();

            let mut collections = Collections::new(
                cust.as_collection(),
                line.as_collection(),
                nats.as_collection(),
                ords.as_collection(),
                part.as_collection(),
                psup.as_collection(),
                regs.as_collection(),
                supp.as_collection(),
            );

            let mut probes = Vec::new();

            match query {
                1 => probes.push(queries::query01::query(&mut collections)),
                2 => probes.push(queries::query02::query(&mut collections)),
                3 => probes.push(queries::query03::query(&mut collections)),
                4 => probes.push(queries::query04::query(&mut collections)),
                5 => probes.push(queries::query05::query(&mut collections)),
                6 => probes.push(queries::query06::query(&mut collections)),
                7 => probes.push(queries::query07::query(&mut collections)),
                8 => probes.push(queries::query08::query(&mut collections)),
                9 => probes.push(queries::query09::query(&mut collections)),
                10 => probes.push(queries::query10::query(&mut collections)),
                11 => probes.push(queries::query11::query(&mut collections)),
                12 => probes.push(queries::query12::query(&mut collections)),
                13 => probes.push(queries::query13::query(&mut collections)),
                14 => probes.push(queries::query14::query(&mut collections)),
                15 => probes.push(queries::query15::query(&mut collections)),
                16 => probes.push(queries::query16::query(&mut collections)),
                17 => probes.push(queries::query17::query(&mut collections)),
                18 => probes.push(queries::query18::query(&mut collections)),
                19 => probes.push(queries::query19::query(&mut collections)),
                20 => probes.push(queries::query20::query(&mut collections)),
                21 => probes.push(queries::query21::query(&mut collections)),
                22 => probes.push(queries::query22::query(&mut collections)),
                _ => panic!("query: {:?} unimplemented", query),
            }

            // return the various input handles, and the list of probes.
            ((cust_in, line_in, nats_in, ords_in, part_in, psup_in, regs_in, supp_in), probes, collections.used)
        });

        // customer.tbl lineitem.tbl    nation.tbl  orders.tbl  part.tbl    partsupp.tbl    region.tbl  supplier.tbl
        let mut customers = if used[0] { load::<Customer>(prefix.as_str(), "customer.tbl", index, peers, logical_batch, physical_batch, 0) } else { Vec::new() };
        let mut lineitems = if used[1] { load::<LineItem>(prefix.as_str(), "lineitem.tbl", index, peers, logical_batch, physical_batch, 1) } else { Vec::new() };
        let mut nations = if used[2] { load::<Nation>(prefix.as_str(), "nation.tbl", index, peers, logical_batch, physical_batch, 2) } else { Vec::new() };
        let mut orders = if used[3] { load::<Order>(prefix.as_str(), "orders.tbl", index, peers, logical_batch, physical_batch, 3) } else { Vec::new() };
        let mut parts = if used[4] { load::<Part>(prefix.as_str(), "part.tbl", index, peers, logical_batch, physical_batch, 4) } else { Vec::new() };
        let mut partsupps = if used[5] { load::<PartSupp>(prefix.as_str(), "partsupp.tbl", index, peers, logical_batch, physical_batch, 5) } else { Vec::new() };
        let mut regions = if used[6] { load::<Region>(prefix.as_str(), "region.tbl", index, peers, logical_batch, physical_batch, 6) } else { Vec::new() };
        let mut suppliers = if used[7] { load::<Supplier>(prefix.as_str(), "supplier.tbl", index, peers, logical_batch, physical_batch, 7) } else { Vec::new() };

        let mut tuples = 0usize;
        tuples += customers.iter().map(|x| x.len()).sum::<usize>();
        tuples += lineitems.iter().map(|x| x.len()).sum::<usize>();
        tuples += nations.iter().map(|x| x.len()).sum::<usize>();
        tuples += orders.iter().map(|x| x.len()).sum::<usize>();
        tuples += parts.iter().map(|x| x.len()).sum::<usize>();
        tuples += partsupps.iter().map(|x| x.len()).sum::<usize>();
        tuples += regions.iter().map(|x| x.len()).sum::<usize>();
        tuples += suppliers.iter().map(|x| x.len()).sum::<usize>();

        // Synchronize before starting the timer.
        let next_round = 1;
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.advance_to(next_round);
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.advance_to(next_round);
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let timer = Instant::now();
        let mut round = 0;
        while customers.len() > 0 || lineitems.len() > 0 || nations.len() > 0 || orders.len() > 0 || parts.len() > 0 || partsupps.len() > 0 || regions.len() > 0 || suppliers.len() > 0 {

            // introduce physical batch of data for each input with remaining data.
            if let Some(mut data) = customers.pop() {
                assert!(data.iter().all(|t| inputs.0.time().le(&t.1)));
                inputs.0.send_batch(&mut data);
            }
            if let Some(mut data) = lineitems.pop() {
                for x in data.iter() {
                    if !inputs.1.time().le(&x.1) {
                        panic!("{:?} but {:?}", inputs.1.time(), &x.1);
                    }
                }
                assert!(data.iter().all(|t| inputs.1.time().le(&t.1)));
                inputs.1.send_batch(&mut data);
            }
            if let Some(mut data) = nations.pop() { inputs.2.send_batch(&mut data); }
            if let Some(mut data) = orders.pop() {
                assert!(data.iter().all(|t| inputs.3.time().le(&t.1)));
                inputs.3.send_batch(&mut data);
            }
            if let Some(mut data) = parts.pop() { inputs.4.send_batch(&mut data); }
            if let Some(mut data) = partsupps.pop() { inputs.5.send_batch(&mut data); }
            if let Some(mut data) = regions.pop() { inputs.6.send_batch(&mut data); }
            if let Some(mut data) = suppliers.pop() { inputs.7.send_batch(&mut data); }

            // catch all inputs up to the same (next) round.
            let next_round = 1 + 8 * (round + 1) * physical_batch;
            inputs.0.advance_to(next_round);
            inputs.1.advance_to(next_round);
            inputs.2.advance_to(next_round);
            inputs.3.advance_to(next_round);
            inputs.4.advance_to(next_round);
            inputs.5.advance_to(next_round);
            inputs.6.advance_to(next_round);
            inputs.7.advance_to(next_round);

            let time = inputs.0.time().clone();
            worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));
            round += 1;
        }

        // Finish outstanding work before stopping the timer.
        let next_round = usize::max_value();
        inputs.0.advance_to(next_round);
        inputs.1.advance_to(next_round);
        inputs.2.advance_to(next_round);
        inputs.3.advance_to(next_round);
        inputs.4.advance_to(next_round);
        inputs.5.advance_to(next_round);
        inputs.6.advance_to(next_round);
        inputs.7.advance_to(next_round);
        let time = inputs.0.time().clone();
        worker.step_while(|| probes.iter().all(|p| p.less_than(&time)));

        let query_name = if query < 10 { format!("q0{}", query) } else { format!("q{}", query) };
        let elapsed = timer.elapsed();
        let nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
        if index == 0 {
            println!("query: {}, elapsed: {:?}, tuples: {:?}, rate: {:?}", query_name, timer.elapsed(), peers * tuples, ((peers * tuples) as f64) / (nanos as f64 / 1000000000.0));
        }

    }).unwrap();
}

pub struct Collections<G: Scope> {
    customers: Collection<G, Customer, isize>,
    lineitems: Collection<G, LineItem, isize>,
    nations: Collection<G, Nation, isize>,
    orders: Collection<G, Order, isize>,
    parts: Collection<G, Part, isize>,
    partsupps: Collection<G, PartSupp, isize>,
    regions: Collection<G, Region, isize>,
    suppliers: Collection<G, Supplier, isize>,
    used: [bool; 8],
}

impl<G: Scope> Collections<G> {
    fn new(
        customers: Collection<G, Customer, isize>,
        lineitems: Collection<G, LineItem, isize>,
        nations: Collection<G, Nation, isize>,
        orders: Collection<G, Order, isize>,
        parts: Collection<G, Part, isize>,
        partsupps: Collection<G, PartSupp, isize>,
        regions: Collection<G, Region, isize>,
        suppliers: Collection<G, Supplier, isize>,
    ) -> Self {

        Collections {
            customers: customers,
            lineitems: lineitems,
            nations: nations,
            orders: orders,
            parts: parts,
            partsupps: partsupps,
            regions: regions,
            suppliers: suppliers,
            used: [false; 8]
        }
    }

    fn customers(&mut self) -> &Collection<G, Customer, isize> { self.used[0] = true; &self.customers }
    fn lineitems(&mut self) -> &Collection<G, LineItem, isize> { self.used[1] = true; &self.lineitems }
    fn nations(&mut self) -> &Collection<G, Nation, isize> { self.used[2] = true; &self.nations }
    fn orders(&mut self) -> &Collection<G, Order, isize> { self.used[3] = true; &self.orders }
    fn parts(&mut self) -> &Collection<G, Part, isize> { self.used[4] = true; &self.parts }
    fn partsupps(&mut self) -> &Collection<G, PartSupp, isize> { self.used[5] = true; &self.partsupps }
    fn regions(&mut self) -> &Collection<G, Region, isize> { self.used[6] = true; &self.regions }
    fn suppliers(&mut self) -> &Collection<G, Supplier, isize> { self.used[7] = true; &self.suppliers }
}

// Returns a sequence of physical batches of ready-to-go timestamped data. Not clear that `input` can exploit the pre-arrangement yet.
fn load<T>(prefix: &str, name: &str, index: usize, peers: usize, logical_batch: usize, physical_batch: usize, off: usize)
    -> Vec<Vec<(T, Product<RootTimestamp, usize>, isize)>>
where T: for<'a> From<&'a str> {

    let mut result = Vec::new();
    let mut buffer = Vec::new();

    let path = format!("{}{}", prefix, name);

    let items_file = File::open(&path).expect("didn't find items file");
    let mut items_reader =  BufReader::new(items_file);
    let mut count = 0;

    let mut line = String::new();

    while items_reader.read_line(&mut line).unwrap() > 0 {

        if count % peers == index {

            let logical = (8 * count / logical_batch) + off;
            let physical = logical / physical_batch;
            let round = physical / 8;

            while result.len() < round {
                result.push(buffer);
                buffer = Vec::with_capacity(2 + logical_batch * physical_batch / peers);
            }

            let item = T::from(line.as_str());
            buffer.push((item, RootTimestamp::new(logical + 1), 1));
        }

        count += 1;

        line.clear();
    }

    if buffer.len() > 0 {
        result.push(buffer);
    }

    result.reverse();
    result
}
<|endoftext|>


<commit_before>#[cfg(target_os = "windows")]
pub use os::windows::application::WindowsApplication as OsApplication;
#[cfg(target_os = "linux")]
pub use os::linux::application::LinuxApplication as OsApplication;

#[cfg(target_os = "windows")]
pub use os::windows::display::WindowsDisplay as OsDisplay;
#[cfg(target_os = "linux")]
pub use os::linux::display::LinuxDisplay as OsDisplay;

use super::frame::RenderFrame;
use super::renderer::Renderer;
use super::event_loop::EventLoop;

pub struct Application {
   pub os_application: OsApplication,
   pub render_frame: RenderFrame,
}

use super::creator::ApplicationCreator;

impl Application {
   pub fn new<'a>() -> ApplicationCreator<'a> {
      let display = match OsDisplay::new() {
         Ok(os_application) => os_application,
         Err(e) => {
            panic!(e.description);
         }
      };

      ApplicationCreator::new(display)
   }

   pub fn create(
      display: OsDisplay,
      title: &str,
      x: u32, y: u32,
      width: u32, height: u32
   ) -> Self {
      let (screen_width, screen_height) = display.screen_size();

      let render_frame = RenderFrame::new(width, height, screen_width, screen_height);

      let os_application = match OsApplication::new(
         display, title, x, y, width, height
      ) {
         Ok(os_application) => os_application,
         Err(e) => {
            panic!(e.description);
         }
      };

      Application {
         os_application: os_application,
         render_frame: render_frame,
      }
   }

   pub fn run(&mut self, renderer: &mut Renderer) {
      let event_loop = EventLoop::new(&self.os_application);

      match event_loop.run(renderer, &mut self.render_frame) {
         Ok(_) => {},
         Err(e) => {
            panic!(e.description);
         }
      }
   }

   pub fn screen_size(&self) -> (u32, u32) {
      self.os_application.screen_size()
   }
}
<commit_msg>Typo in polydraw::application<commit_after>#[cfg(target_os = "windows")]
pub use os::windows::application::WindowsApplication as OsApplication;
#[cfg(target_os = "linux")]
pub use os::linux::application::LinuxApplication as OsApplication;

#[cfg(target_os = "windows")]
pub use os::windows::display::WindowsDisplay as OsDisplay;
#[cfg(target_os = "linux")]
pub use os::linux::display::LinuxDisplay as OsDisplay;

use super::frame::RenderFrame;
use super::renderer::Renderer;
use super::event_loop::EventLoop;

pub struct Application {
   pub os_application: OsApplication,
   pub render_frame: RenderFrame,
}

use super::creator::ApplicationCreator;

impl Application {
   pub fn new<'a>() -> ApplicationCreator<'a> {
      let display = match OsDisplay::new() {
         Ok(display) => display,
         Err(e) => {
            panic!(e.description);
         }
      };

      ApplicationCreator::new(display)
   }

   pub fn create(
      display: OsDisplay,
      title: &str,
      x: u32, y: u32,
      width: u32, height: u32
   ) -> Self {
      let (screen_width, screen_height) = display.screen_size();

      let render_frame = RenderFrame::new(width, height, screen_width, screen_height);

      let os_application = match OsApplication::new(
         display, title, x, y, width, height
      ) {
         Ok(os_application) => os_application,
         Err(e) => {
            panic!(e.description);
         }
      };

      Application {
         os_application: os_application,
         render_frame: render_frame,
      }
   }

   pub fn run(&mut self, renderer: &mut Renderer) {
      let event_loop = EventLoop::new(&self.os_application);

      match event_loop.run(renderer, &mut self.render_frame) {
         Ok(_) => {},
         Err(e) => {
            panic!(e.description);
         }
      }
   }

   pub fn screen_size(&self) -> (u32, u32) {
      self.os_application.screen_size()
   }
}
<|endoftext|>


<commit_before>extern crate "cargo-registry" as cargo_registry;
extern crate migrate;
extern crate postgres;
extern crate r2d2;

use std::os;
use migrate::Migration;
use postgres::{PostgresTransaction, PostgresResult};

fn main() {
    let db_config = r2d2::Config {
        pool_size: 1,
        helper_tasks: 1,
        test_on_check_out: false,
    };
    let database = cargo_registry::db::pool(env("DATABASE_URL").as_slice(),
                                            db_config);
    let conn = database.get().unwrap();
    let migrations = migrations();

    if os::args().as_slice().get(1).map(|s| s.as_slice()) == Some("rollback") {
        rollback(conn.transaction().unwrap(), migrations).unwrap();
    } else {
        apply(conn.transaction().unwrap(), migrations).unwrap();
    }

    fn env(s: &str) -> String {
        match os::getenv(s) {
            Some(s) => s,
            None => fail!("must have `{}` defined", s),
        }
    }
}

fn apply(tx: PostgresTransaction,
         migrations: Vec<Migration>) -> PostgresResult<()> {
    let mut mgr = try!(migrate::Manager::new(tx));
    for m in migrations.into_iter() {
        try!(mgr.apply(m));
    }
    mgr.set_commit();
    mgr.finish()
}

fn rollback(tx: PostgresTransaction,
            migrations: Vec<Migration>) -> PostgresResult<()> {
    let mut mgr = try!(migrate::Manager::new(tx));
    for m in migrations.into_iter().rev() {
        if mgr.contains(m.version()) {
            try!(mgr.rollback(m));
            break
        }
    }
    mgr.set_commit();
    mgr.finish()
}

fn migrations() -> Vec<Migration> {
    // Generate a new id via `date +"%Y%m%d%H%M%S"`
    vec![
        Migration::add_table(20140924113530, "users", "
            id              SERIAL PRIMARY KEY,
            email           VARCHAR NOT NULL UNIQUE,
            gh_access_token VARCHAR NOT NULL,
            api_token       VARCHAR NOT NULL
        "),
        Migration::add_table(20140924114003, "packages", "
            id              SERIAL PRIMARY KEY,
            name            VARCHAR NOT NULL UNIQUE,
            user_id         INTEGER NOT NULL
        "),
        Migration::add_table(20140924114059, "versions", "
            id              SERIAL PRIMARY KEY,
            package_id      INTEGER NOT NULL,
            num             VARCHAR NOT NULL UNIQUE
        "),
        Migration::run(20140924115329,
                       format!("ALTER TABLE versions ADD CONSTRAINT \
                                unique_num UNIQUE (package_id, num)"),
                       format!("ALTER TABLE versions DROP CONSTRAINT \
                                unique_num")),
        Migration::add_table(20140924120803, "version_dependencies", "
            version_id      INTEGER NOT NULL,
            depends_on_id   INTEGER NOT NULL
        "),
        Migration::add_column(20140925132248, "packages", "updated_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::add_column(20140925132249, "packages", "created_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::new(20140925132250, proc(tx) {
            try!(tx.execute("UPDATE packages SET updated_at = now() \
                             WHERE updated_at IS NULL", []));
            try!(tx.execute("UPDATE packages SET created_at = now() \
                             WHERE created_at IS NULL", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::add_column(20140925132251, "versions", "updated_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::add_column(20140925132252, "versions", "created_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::new(20140925132253, proc(tx) {
            try!(tx.execute("UPDATE versions SET updated_at = now() \
                             WHERE updated_at IS NULL", []));
            try!(tx.execute("UPDATE versions SET created_at = now() \
                             WHERE created_at IS NULL", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::new(20140925132254, proc(tx) {
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN updated_at \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN created_at \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE packages ALTER COLUMN updated_at \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE packages ALTER COLUMN created_at \
                             DROP DEFAULT", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::add_table(20140925153704, "metadata", "
            total_downloads        BIGINT NOT NULL
        "),
        Migration::new(20140925153705, proc(tx) {
            try!(tx.execute("INSERT INTO metadata (total_downloads) \
                             VALUES ($1)", &[&0i64]));
            Ok(())
        }, proc(tx) {
            try!(tx.execute("DELETE FROM metadata", [])); Ok(())
        }),
        Migration::add_column(20140925161623, "packages", "downloads",
                              "INTEGER NOT NULL DEFAULT 0"),
        Migration::add_column(20140925161624, "versions", "downloads",
                              "INTEGER NOT NULL DEFAULT 0"),
        Migration::new(20140925161625, proc(tx) {
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN downloads \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE packages ALTER COLUMN downloads \
                             DROP DEFAULT", []));
            Ok(())
        }, proc(_) Ok(())),
    ]
}
<commit_msg>Keep track of a package's maximum version<commit_after>extern crate "cargo-registry" as cargo_registry;
extern crate migrate;
extern crate postgres;
extern crate r2d2;

use std::os;
use migrate::Migration;
use postgres::{PostgresTransaction, PostgresResult};

use cargo_registry::package::Package;

fn main() {
    let db_config = r2d2::Config {
        pool_size: 1,
        helper_tasks: 1,
        test_on_check_out: false,
    };
    let database = cargo_registry::db::pool(env("DATABASE_URL").as_slice(),
                                            db_config);
    let conn = database.get().unwrap();
    let migrations = migrations();

    if os::args().as_slice().get(1).map(|s| s.as_slice()) == Some("rollback") {
        rollback(conn.transaction().unwrap(), migrations).unwrap();
    } else {
        apply(conn.transaction().unwrap(), migrations).unwrap();
    }

    fn env(s: &str) -> String {
        match os::getenv(s) {
            Some(s) => s,
            None => fail!("must have `{}` defined", s),
        }
    }
}

fn apply(tx: PostgresTransaction,
         migrations: Vec<Migration>) -> PostgresResult<()> {
    let mut mgr = try!(migrate::Manager::new(tx));
    for m in migrations.into_iter() {
        try!(mgr.apply(m));
    }
    mgr.set_commit();
    mgr.finish()
}

fn rollback(tx: PostgresTransaction,
            migrations: Vec<Migration>) -> PostgresResult<()> {
    let mut mgr = try!(migrate::Manager::new(tx));
    for m in migrations.into_iter().rev() {
        if mgr.contains(m.version()) {
            try!(mgr.rollback(m));
            break
        }
    }
    mgr.set_commit();
    mgr.finish()
}

fn migrations() -> Vec<Migration> {
    // Generate a new id via `date +"%Y%m%d%H%M%S"`
    vec![
        Migration::add_table(20140924113530, "users", "
            id              SERIAL PRIMARY KEY,
            email           VARCHAR NOT NULL UNIQUE,
            gh_access_token VARCHAR NOT NULL,
            api_token       VARCHAR NOT NULL
        "),
        Migration::add_table(20140924114003, "packages", "
            id              SERIAL PRIMARY KEY,
            name            VARCHAR NOT NULL UNIQUE,
            user_id         INTEGER NOT NULL
        "),
        Migration::add_table(20140924114059, "versions", "
            id              SERIAL PRIMARY KEY,
            package_id      INTEGER NOT NULL,
            num             VARCHAR NOT NULL UNIQUE
        "),
        Migration::run(20140924115329,
                       format!("ALTER TABLE versions ADD CONSTRAINT \
                                unique_num UNIQUE (package_id, num)"),
                       format!("ALTER TABLE versions DROP CONSTRAINT \
                                unique_num")),
        Migration::add_table(20140924120803, "version_dependencies", "
            version_id      INTEGER NOT NULL,
            depends_on_id   INTEGER NOT NULL
        "),
        Migration::add_column(20140925132248, "packages", "updated_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::add_column(20140925132249, "packages", "created_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::new(20140925132250, proc(tx) {
            try!(tx.execute("UPDATE packages SET updated_at = now() \
                             WHERE updated_at IS NULL", []));
            try!(tx.execute("UPDATE packages SET created_at = now() \
                             WHERE created_at IS NULL", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::add_column(20140925132251, "versions", "updated_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::add_column(20140925132252, "versions", "created_at",
                              "TIMESTAMP NOT NULL DEFAULT now()"),
        Migration::new(20140925132253, proc(tx) {
            try!(tx.execute("UPDATE versions SET updated_at = now() \
                             WHERE updated_at IS NULL", []));
            try!(tx.execute("UPDATE versions SET created_at = now() \
                             WHERE created_at IS NULL", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::new(20140925132254, proc(tx) {
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN updated_at \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN created_at \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE packages ALTER COLUMN updated_at \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE packages ALTER COLUMN created_at \
                             DROP DEFAULT", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::add_table(20140925153704, "metadata", "
            total_downloads        BIGINT NOT NULL
        "),
        Migration::new(20140925153705, proc(tx) {
            try!(tx.execute("INSERT INTO metadata (total_downloads) \
                             VALUES ($1)", &[&0i64]));
            Ok(())
        }, proc(tx) {
            try!(tx.execute("DELETE FROM metadata", [])); Ok(())
        }),
        Migration::add_column(20140925161623, "packages", "downloads",
                              "INTEGER NOT NULL DEFAULT 0"),
        Migration::add_column(20140925161624, "versions", "downloads",
                              "INTEGER NOT NULL DEFAULT 0"),
        Migration::new(20140925161625, proc(tx) {
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN downloads \
                             DROP DEFAULT", []));
            try!(tx.execute("ALTER TABLE packages ALTER COLUMN downloads \
                             DROP DEFAULT", []));
            Ok(())
        }, proc(_) Ok(())),
        Migration::add_column(20140926130044, "packages", "max_version",
                              "VARCHAR"),
        Migration::new(20140926130045, proc(tx) {
            let stmt = try!(tx.prepare("SELECT * FROM packages"));
            for row in try!(stmt.query(&[])) {
                let pkg = Package::from_row(&row);
                let versions = pkg.versions(tx).unwrap();
                let v = versions.iter().max_by(|v| &v.num).unwrap();
                let max = v.num.to_string();
                try!(tx.execute("UPDATE packages SET max_version = $1 \
                                 WHERE id = $2",
                                &[&max, &pkg.id]));
            }
            Ok(())
        }, proc(_) Ok(())),
        Migration::new(20140926130046, proc(tx) {
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN downloads \
                             SET NOT NULL", []));
            Ok(())
        }, proc(tx) {
            try!(tx.execute("ALTER TABLE versions ALTER COLUMN downloads \
                             DROP NOT NULL", []));
            Ok(())
        }),
    ]
}
<|endoftext|>