<commit_before>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::error::Error;
use std::rc::Rc;

pub trait Loadable<K,E> {
    fn load(_key: &K) -> Result<Self,E>
        where Self: Sized;
}

pub struct AssetCache<K,V>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
}

impl<K,V> AssetCache<K,V>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        let map = BTreeMap::new();
        AssetCache {
            contents: map,
        }
    }

    /// Gets the given asset, loading it if necessary.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get<E>(&mut self, key: &K) -> Result<Rc<V>,E>
        where V: Loadable<K,E> {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone())
        };

        let v = try!(V::load(key));
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K,E> {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

/// An AssetCache that owns some State
/// object, which then gets passed to and
/// updated by the Load function.
pub struct StatefulAssetCache<K,V,S>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
    loader: fn(&K, &mut S) -> V,
    state: S,
}

impl<K,V,S> StatefulAssetCache<K,V,S>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new(loaderfunc: fn(&K, &mut S) -> V, state: S) -> Self {
        let map = BTreeMap::new();
        StatefulAssetCache {
            contents: map,
            loader: loaderfunc,
            state: state,
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get(&mut self, key: &K) -> Rc<V> {
        let loader = self.loader;
        let state = &mut self.state;
        let f = || {
            let item = loader(key, state);
            Rc::new(item)
        };
        let entry = self.contents.entry(key.clone());
        //let loader = self.loader;
        entry.or_insert_with(f).clone()
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload(&mut self, keys: &[K]) {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

mod tests {
    use super::*;

    impl Loadable<String,()> for String {
        fn load(key:&String) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<String,String>::new();
        assert!(!a.loaded(&("foo".to_string())));
        let s1 = a.get(&"foo".to_string()).unwrap();
        assert_eq!(*s1, "foo".to_string());
        assert!(a.loaded(&("foo".to_string())));
    }

    #[test]
    fn test_stateful_assetcache() {
        fn loader(s: &&str, loaderinfo: &mut u32) -> String {
            *loaderinfo += 1;
            match *s {
                "foo" => "FooBaz".to_owned(),
                "bar" => "BarBaz".to_owned(),
                _ => "Something else".to_owned(),
            }
        }

        let mut a = StatefulAssetCache::new(loader, 0);
        assert_eq!(a.state, 0);
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo");
        assert_eq!(*s1, "FooBaz".to_owned());
        assert_eq!(a.state, 1);
        assert!(a.loaded(&"foo"));
    }

}
<commit_msg>Updated asset cache tests to use Loadable trait.<commit_after>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::error::Error;
use std::rc::Rc;

pub trait Loadable<K,E> {
    fn load(_key: &K) -> Result<Self,E>
        where Self: Sized;
}

pub struct AssetCache<K,V>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
}

impl<K,V> AssetCache<K,V>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        let map = BTreeMap::new();
        AssetCache {
            contents: map,
        }
    }

    /// Gets the given asset, loading it if necessary.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get<E>(&mut self, key: &K) -> Result<Rc<V>,E>
        where V: Loadable<K,E> {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone())
        };

        let v = try!(V::load(key));
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K,E> {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

/// An AssetCache that owns some State
/// object, which then gets passed to and
/// updated by the Load function.
pub struct StatefulAssetCache<K,V,S>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
    loader: fn(&K, &mut S) -> V,
    state: S,
}

impl<K,V,S> StatefulAssetCache<K,V,S>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new(loaderfunc: fn(&K, &mut S) -> V, state: S) -> Self {
        let map = BTreeMap::new();
        StatefulAssetCache {
            contents: map,
            loader: loaderfunc,
            state: state,
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get(&mut self, key: &K) -> Rc<V> {
        let loader = self.loader;
        let state = &mut self.state;
        let f = || {
            let item = loader(key, state);
            Rc::new(item)
        };
        let entry = self.contents.entry(key.clone());
        //let loader = self.loader;
        entry.or_insert_with(f).clone()
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload(&mut self, keys: &[K]) {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

mod tests {
    use super::*;

    impl<'a> Loadable<&'a str,()> for String {
        fn load(key:&&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str,String>::new();
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo").unwrap();
        assert_eq!(*s1, "foo");
        assert!(a.loaded(&"foo"));
    }

    #[test]
    fn test_stateful_assetcache() {
        fn loader(s: &&str, loaderinfo: &mut u32) -> String {
            *loaderinfo += 1;
            match *s {
                "foo" => "FooBaz".to_owned(),
                "bar" => "BarBaz".to_owned(),
                _ => "Something else".to_owned(),
            }
        }

        let mut a = StatefulAssetCache::new(loader, 0);
        assert_eq!(a.state, 0);
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo");
        assert_eq!(*s1, "FooBaz".to_owned());
        assert_eq!(a.state, 1);
        assert!(a.loaded(&"foo"));
    }

}
<|endoftext|>


<commit_before>/// Escape characters in a string that is to be inserted in Markdown
///
/// This only escapes characters that may be present in inline Markdown
/// to avoid string in curly attributes etc from being parsed as
/// emphasis, strong, links etc. The list of escaped characters may
/// need to be augmented in the future.
pub(crate) fn escape(string: &str) -> String {
    string
        .replace('_', "\\_")
        .replace('*', "\\*")
        .replace('[', "\\[")
        .replace('$', "\\$")
}

/// Unescape characters
///
/// See [`escape`] for which characters need to be unescaped.
pub(crate) fn unescape(string: &str) -> String {
    string
        .replace("\\_", "_")
        .replace("\\*", "*")
        .replace("\\[", "[")
        .replace("\\$", "$")
}
<commit_msg>refactor(Markdown codec): Do not escape opening square bracket<commit_after>/// Escape characters in a string that is to be inserted in Markdown
///
/// This only escapes characters that may be present in inline Markdown
/// to avoid string in curly attributes etc from being parsed as
/// emphasis, strong etc. The list of escaped characters may
/// need to be augmented in the future.
///
/// Previously we also escaped '[' but that is often used in JSON
/// values for enum and array parameters so is now not escaped.
pub(crate) fn escape(string: &str) -> String {
    string
        .replace('_', "\\_")
        .replace('*', "\\*")
        .replace('$', "\\$")
}

/// Unescape characters
///
/// See [`escape`] for which characters need to be unescaped.
pub(crate) fn unescape(string: &str) -> String {
    string
        .replace("\\_", "_")
        .replace("\\*", "*")
        .replace("\\$", "$")
}
<|endoftext|>


<commit_before>use time::Duration;
use time::PrimitiveDateTime as DateTime;

// Returns a DateTime one billion seconds after start.
pub fn after(start: DateTime) -> DateTime {
    let gigasecond: Duration = Duration::SECOND * 1_000_000_000;
    return start + gigasecond;
}
<commit_msg>Make gigasecond a constant<commit_after>use time::Duration;
use time::PrimitiveDateTime as DateTime;

const GIGASECOND: Duration = Duration::new(1_000_000_000, 0);

// Returns a DateTime one billion seconds after start.
pub fn after(start: DateTime) -> DateTime {
    return start + GIGASECOND;
}
<|endoftext|>


<commit_before>use ffmpeg_sys;
use libc::*;
use std::cmp;
use std::ffi::{ CStr, CString };

use errors::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct Rational {
    pub numerator: c_int,
    pub denominator: c_int,
}

#[derive(Clone, Copy)]
pub struct Codec {
    ptr: *mut ffmpeg_sys::AVCodec,
}

unsafe impl Send for Codec {}
unsafe impl Sync for Codec {}

pub struct PixelFormats {
    codec: Codec,
    index: isize,
}

pub struct Context {
    ptr: *mut ffmpeg_sys::AVCodecContext,
}

impl From<(i32, i32)> for Rational {
    fn from((numerator, denominator): (i32, i32)) -> Self {
        Self {
            numerator,
            denominator,
        }
    }
}

impl Codec {
    pub fn description(self) -> String {
        unsafe {
            CStr::from_ptr((*self.ptr).long_name).to_string_lossy().into_owned()
        }
    }

    pub fn kind(self) -> ffmpeg_sys::AVMediaType {
        unsafe {
            (*self.ptr).kind
        }
    }

    pub fn is_video(self) -> bool {
        self.kind() == ffmpeg_sys::AVMediaType::AVMEDIA_TYPE_VIDEO
    }

    pub fn pixel_formats(self) -> Option<PixelFormats> {
        unsafe {
            if (*self.ptr).pix_fmts.is_null() {
                None
            } else {
                Some(PixelFormats::new(self))
            }
        }
    }

    pub fn context(self) -> Result<Context> {
        let ptr = unsafe {
            ffmpeg_sys::avcodec_alloc_context3(self.ptr)
        };

        ensure!(!ptr.is_null(), "unable to allocate the codec context");

        Ok(Context { ptr })
    }
}

impl PixelFormats {
    fn new(codec: Codec) -> Self {
        Self {
            codec,
            index: 0,
        }
    }
}

impl Iterator for PixelFormats {
    type Item = ffmpeg_sys::AVPixelFormat;

    fn next(&mut self) -> Option<Self::Item> {
        let format = unsafe {
            *(*self.codec.ptr).pix_fmts.offset(self.index)
        };

        if format == ffmpeg_sys::AVPixelFormat::AV_PIX_FMT_NONE {
            None
        } else {
            self.index += 1;
            Some(format)
        }
    }
}

impl Context {
    pub fn width(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).width) as u32
        }
    }

    pub fn set_width(&mut self, width: u32) {
        unsafe {
            (*self.ptr).width = cmp::min(width, c_int::max_value() as u32) as c_int;
        }
    }

    pub fn height(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).height) as u32
        }
    }

    pub fn set_height(&mut self, height: u32) {
        unsafe {
            (*self.ptr).height = cmp::min(height, c_int::max_value() as u32) as c_int;
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            ffmpeg_sys::avcodec_free_context(&mut self.ptr);
        }
    }
}

pub fn initialize() {
    unsafe {
        ffmpeg_sys::avcodec_register_all();
    }
}

pub fn find_encoder_by_name(name: &str) -> Result<Option<Codec>> {
    let name = CString::new(name).chain_err(|| "could not convert name to CString")?;

    let codec = unsafe {
        ffmpeg_sys::avcodec_find_encoder_by_name(name.as_ptr())
    };

    if codec.is_null() {
        Ok(None)
    } else {
        Ok(Some(Codec { ptr: codec }))
    }
}
<commit_msg>Make Rational default repr with Rust types<commit_after>use ffmpeg_sys;
use libc::*;
use std::cmp;
use std::ffi::{ CStr, CString };

use errors::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Rational {
    pub numerator: i32,
    pub denominator: i32,
}

#[derive(Clone, Copy)]
pub struct Codec {
    ptr: *mut ffmpeg_sys::AVCodec,
}

unsafe impl Send for Codec {}
unsafe impl Sync for Codec {}

pub struct PixelFormats {
    codec: Codec,
    index: isize,
}

pub struct Context {
    ptr: *mut ffmpeg_sys::AVCodecContext,
}

impl From<(i32, i32)> for Rational {
    fn from((numerator, denominator): (i32, i32)) -> Self {
        Self {
            numerator,
            denominator,
        }
    }
}

impl From<ffmpeg_sys::AVRational> for Rational {
    fn from(rational: ffmpeg_sys::AVRational) -> Self {
        Self {
            numerator: rational.num,
            denominator: rational.den,
        }
    }
}

impl From<Rational> for ffmpeg_sys::AVRational {
    fn from(rational: Rational) -> Self {
        Self {
            num: rational.numerator,
            den: rational.denominator,
        }
    }
}

impl Codec {
    pub fn description(self) -> String {
        unsafe {
            CStr::from_ptr((*self.ptr).long_name).to_string_lossy().into_owned()
        }
    }

    pub fn kind(self) -> ffmpeg_sys::AVMediaType {
        unsafe {
            (*self.ptr).kind
        }
    }

    pub fn is_video(self) -> bool {
        self.kind() == ffmpeg_sys::AVMediaType::AVMEDIA_TYPE_VIDEO
    }

    pub fn pixel_formats(self) -> Option<PixelFormats> {
        unsafe {
            if (*self.ptr).pix_fmts.is_null() {
                None
            } else {
                Some(PixelFormats::new(self))
            }
        }
    }

    pub fn context(self) -> Result<Context> {
        let ptr = unsafe {
            ffmpeg_sys::avcodec_alloc_context3(self.ptr)
        };

        ensure!(!ptr.is_null(), "unable to allocate the codec context");

        Ok(Context { ptr })
    }
}

impl PixelFormats {
    fn new(codec: Codec) -> Self {
        Self {
            codec,
            index: 0,
        }
    }
}

impl Iterator for PixelFormats {
    type Item = ffmpeg_sys::AVPixelFormat;

    fn next(&mut self) -> Option<Self::Item> {
        let format = unsafe {
            *(*self.codec.ptr).pix_fmts.offset(self.index)
        };

        if format == ffmpeg_sys::AVPixelFormat::AV_PIX_FMT_NONE {
            None
        } else {
            self.index += 1;
            Some(format)
        }
    }
}

impl Context {
    pub fn width(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).width) as u32
        }
    }

    pub fn set_width(&mut self, width: u32) {
        unsafe {
            (*self.ptr).width = cmp::min(width, c_int::max_value() as u32) as c_int;
        }
    }

    pub fn height(&self) -> u32 {
        unsafe {
            cmp::max(0, (*self.ptr).height) as u32
        }
    }

    pub fn set_height(&mut self, height: u32) {
        unsafe {
            (*self.ptr).height = cmp::min(height, c_int::max_value() as u32) as c_int;
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            ffmpeg_sys::avcodec_free_context(&mut self.ptr);
        }
    }
}

pub fn initialize() {
    unsafe {
        ffmpeg_sys::avcodec_register_all();
    }
}

pub fn find_encoder_by_name(name: &str) -> Result<Option<Codec>> {
    let name = CString::new(name).chain_err(|| "could not convert name to CString")?;

    let codec = unsafe {
        ffmpeg_sys::avcodec_find_encoder_by_name(name.as_ptr())
    };

    if codec.is_null() {
        Ok(None)
    } else {
        Ok(Some(Codec { ptr: codec }))
    }
}
<|endoftext|>


<commit_before>use docopt::{self, Docopt, ArgvMap};
use std::io::{self, Write};
use std::process;
use std::path::Path;
use std::error;
use std::result;
use std::fmt;
use mprovision as mp;

const USAGE: &'static str = "
mprovision
A tool that helps iOS developers to manage mobileprovision files.

Usage:
  mprovision list [--filter <text>] [--expires-in-days <days>] [<directory>]
  mprovision (-h | --help)
  mprovision --version

Options:
  -h --help     Show this help message.
  --version     Show version.
";

#[derive(Debug)]
pub enum Command {
    List,
}

pub type Result = result::Result<Command, Error>;

#[derive(Debug)]
pub enum Error {
    Lib(mp::Error),
    Docopt(docopt::Error),
    Custom(String),
}

impl Error {
    pub fn exit(&self) -> ! {
        match *self {
            Error::Docopt(ref e) => e.exit(),
            _ => {
                writeln!(&mut io::stderr(), "{}", self).unwrap();
                process::exit(1);
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Lib(ref e) => e.description(),
            Error::Docopt(ref e) => e.description(),
            Error::Custom(ref e) => e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Lib(ref e) => Some(e),
            Error::Docopt(ref e) => Some(e),
            Error::Custom(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Lib(ref e) => error::Error::description(e).fmt(f),
            Error::Docopt(ref e) => error::Error::description(e).fmt(f),
            Error::Custom(ref e) => e.fmt(f),
        }
    }
}

impl From<mp::Error> for Error {
    fn from(e: mp::Error) -> Self {
        Error::Lib(e)
    }
}

impl From<docopt::Error> for Error {
    fn from(e: docopt::Error) -> Self {
        Error::Docopt(e)
    }
}

pub fn parse<I, S>(args: I) -> Result
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let version = format!("mprovision {}", version!());
    let argv_map = Docopt::new(USAGE)?.argv(args).version(Some(version)).parse()?;
    Ok(Command::List)
}

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

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "."])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--filter abc"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--filter abc", "."])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--expires-in-days 0"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--expires-in-days 0", "."])).to(be_ok());
    }
}
<commit_msg>Handle some params for the list command<commit_after>use docopt::{self, Docopt, ArgvMap};
use std::io::{self, Write};
use std::process;
use std::path::{Path, PathBuf};
use std::error;
use std::result;
use std::fmt;
use mprovision as mp;

const USAGE: &'static str = "
mprovision
A tool that helps iOS developers to manage mobileprovision files.

Usage:
  mprovision list [--filter <text>] [--expires-in-days <days>] [<directory>]
  mprovision (-h | --help)
  mprovision --version

Options:
  -h --help     Show this help message.
  --version     Show version.
";

#[derive(Debug, PartialEq)]
pub enum Command {
    List(ListParams),
}

#[derive(Debug, Default, PartialEq)]
pub struct ListParams {
    pub filter: Option<String>,
    pub expires_in_days: Option<i64>,
    pub directory: Option<PathBuf>,
}

pub type Result = result::Result<Command, Error>;

#[derive(Debug)]
pub enum Error {
    Lib(mp::Error),
    Docopt(docopt::Error),
    Custom(String),
}

impl Error {
    pub fn exit(&self) -> ! {
        match *self {
            Error::Docopt(ref e) => e.exit(),
            _ => {
                writeln!(&mut io::stderr(), "{}", self).unwrap();
                process::exit(1);
            }
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Lib(ref e) => e.description(),
            Error::Docopt(ref e) => e.description(),
            Error::Custom(ref e) => e,
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Lib(ref e) => Some(e),
            Error::Docopt(ref e) => Some(e),
            Error::Custom(_) => None,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Lib(ref e) => error::Error::description(e).fmt(f),
            Error::Docopt(ref e) => error::Error::description(e).fmt(f),
            Error::Custom(ref e) => e.fmt(f),
        }
    }
}

impl From<mp::Error> for Error {
    fn from(e: mp::Error) -> Self {
        Error::Lib(e)
    }
}

impl From<docopt::Error> for Error {
    fn from(e: docopt::Error) -> Self {
        Error::Docopt(e)
    }
}

pub fn parse<I, S>(args: I) -> Result
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let version = format!("mprovision {}", version!());
    let argv_map = Docopt::new(USAGE)?.argv(args).version(Some(version)).parse()?;
    if argv_map.get_bool("list") {
        let mut params = ListParams::default();
        if argv_map.get_bool("--filter") {
            let text = argv_map.get_str("--filter");
            if text.is_empty() {
                return Err(Error::Custom("<text> is empty".to_string()));
            }
            params.filter = Some(text.to_string());
        }
        if argv_map.get_bool("--expires-in-days") {
            if let Some(days) = argv_map.get_str("--expires-in-days").parse::<i64>().ok() {
                if days < 0 || days > 365 {
                    return Err(Error::Custom("<days> should be between 0 and 365".to_string()));
                }
                params.expires_in_days = Some(days);
            }
        }
        params.directory = directory(&argv_map);
        Ok(Command::List(params))
    } else {
        Err(Error::Custom("Command is not implemented".to_string()))
    }
}

fn directory(args: &::docopt::ArgvMap) -> Option<PathBuf> {
    let dir_name = args.get_str("<directory>");
    if dir_name.is_empty() {
        None
    } else {
        Some(dir_name.into())
    }
}

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

    #[test]
    fn list_command() {
        expect!(parse(&["mprovision", "list"]))
            .to(be_ok().value(Command::List(ListParams::default())));

        expect!(parse(&["mprovision", "list", "--filter", ""])).to(be_err());

        expect!(parse(&["mprovision", "list", "."])).to(be_ok().value(Command::List(ListParams {
            filter: None,
            expires_in_days: None,
            directory: Some(".".into()),
        })));
        expect!(parse(&["mprovision", "list", "--filter abc"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--filter abc", "."])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--expires-in-days 0"])).to(be_ok());
        expect!(parse(&["mprovision", "list", "--expires-in-days 0", "."])).to(be_ok());
    }
}
<|endoftext|>


<commit_before>use krate::Crate;
use schema::badges;
use util::CargoResult;

use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use serde_json;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(tag = "badge_type", content = "attributes")]
pub enum Badge {
    #[serde(rename = "travis-ci")]
    TravisCi {
        repository: String,
        branch: Option<String>,
    },
    #[serde(rename = "appveyor")]
    Appveyor {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "gitlab")]
    GitLab {
        repository: String,
        branch: Option<String>,
    },
    #[serde(rename = "is-it-maintained-issue-resolution")]
    IsItMaintainedIssueResolution { repository: String },
    #[serde(rename = "is-it-maintained-open-issues")]
    IsItMaintainedOpenIssues { repository: String },
    #[serde(rename = "codecov")]
    Codecov {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "coveralls")]
    Coveralls {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
}

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl Queryable<badges::SqlType, Pg> for Badge {
    type Row = (i32, String, serde_json::Value);

    fn build((_, badge_type, attributes): Self::Row) -> Self {
        let json = json!({"badge_type": badge_type, "attributes": attributes});
        serde_json::from_value(json).expect("Invalid CI badge in the database")
    }
}

impl Badge {
    pub fn encodable(self) -> EncodableBadge {
        serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
    }

    pub fn badge_type(&self) -> &'static str {
        match *self {
            Badge::TravisCi { .. } => "travis-ci",
            Badge::Appveyor { .. } => "appveyor",
            Badge::GitLab { .. } => "gitlab",
            Badge::IsItMaintainedIssueResolution { .. } => "is-it-maintained-issue-resolution",
            Badge::IsItMaintainedOpenIssues { .. } => "is-it-maintained-open-issues",
            Badge::Codecov { .. } => "codecov",
            Badge::Coveralls { .. } => "coveralls",
        }
    }

    pub fn update_crate<'a>(
        conn: &PgConnection,
        krate: &Crate,
        badges: Option<&'a HashMap<String, HashMap<String, String>>>,
    ) -> CargoResult<Vec<&'a str>> {
        use diesel::{insert, delete};

        #[derive(Insertable)]
        #[table_name = "badges"]
        struct NewBadge<'a> {
            crate_id: i32,
            badge_type: &'a str,
            attributes: serde_json::Value,
        }

        let mut invalid_badges = vec![];
        let mut new_badges = vec![];

        if let Some(badges) = badges {
            for (k, v) in badges {
                let attributes_json = serde_json::to_value(v).unwrap();

                let json = json!({"badge_type": k, "attributes": attributes_json});
                if serde_json::from_value::<Badge>(json).is_ok() {
                    new_badges.push(NewBadge {
                        crate_id: krate.id,
                        badge_type: &**k,
                        attributes: attributes_json,
                    });
                } else {
                    invalid_badges.push(&**k);
                }
            }
        }

        conn.transaction(|| {
            delete(badges::table.filter(badges::crate_id.eq(krate.id)))
                .execute(conn)?;
            insert(&new_badges).into(badges::table).execute(conn)?;
            Ok(invalid_badges)
        })
    }
}
<commit_msg>Use serde rename_all = "kebab-case"<commit_after>use krate::Crate;
use schema::badges;
use util::CargoResult;

use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use serde_json;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", tag = "badge_type", content = "attributes")]
pub enum Badge {
    TravisCi {
        repository: String,
        branch: Option<String>,
    },
    Appveyor {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "gitlab")]
    GitLab {
        repository: String,
        branch: Option<String>,
    },
    IsItMaintainedIssueResolution { repository: String },
    IsItMaintainedOpenIssues { repository: String },
    Codecov {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    Coveralls {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
}

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl Queryable<badges::SqlType, Pg> for Badge {
    type Row = (i32, String, serde_json::Value);

    fn build((_, badge_type, attributes): Self::Row) -> Self {
        let json = json!({"badge_type": badge_type, "attributes": attributes});
        serde_json::from_value(json).expect("Invalid CI badge in the database")
    }
}

impl Badge {
    pub fn encodable(self) -> EncodableBadge {
        serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
    }

    pub fn badge_type(&self) -> &'static str {
        match *self {
            Badge::TravisCi { .. } => "travis-ci",
            Badge::Appveyor { .. } => "appveyor",
            Badge::GitLab { .. } => "gitlab",
            Badge::IsItMaintainedIssueResolution { .. } => "is-it-maintained-issue-resolution",
            Badge::IsItMaintainedOpenIssues { .. } => "is-it-maintained-open-issues",
            Badge::Codecov { .. } => "codecov",
            Badge::Coveralls { .. } => "coveralls",
        }
    }

    pub fn update_crate<'a>(
        conn: &PgConnection,
        krate: &Crate,
        badges: Option<&'a HashMap<String, HashMap<String, String>>>,
    ) -> CargoResult<Vec<&'a str>> {
        use diesel::{insert, delete};

        #[derive(Insertable)]
        #[table_name = "badges"]
        struct NewBadge<'a> {
            crate_id: i32,
            badge_type: &'a str,
            attributes: serde_json::Value,
        }

        let mut invalid_badges = vec![];
        let mut new_badges = vec![];

        if let Some(badges) = badges {
            for (k, v) in badges {
                let attributes_json = serde_json::to_value(v).unwrap();

                let json = json!({"badge_type": k, "attributes": attributes_json});
                if serde_json::from_value::<Badge>(json).is_ok() {
                    new_badges.push(NewBadge {
                        crate_id: krate.id,
                        badge_type: &**k,
                        attributes: attributes_json,
                    });
                } else {
                    invalid_badges.push(&**k);
                }
            }
        }

        conn.transaction(|| {
            delete(badges::table.filter(badges::crate_id.eq(krate.id)))
                .execute(conn)?;
            insert(&new_badges).into(badges::table).execute(conn)?;
            Ok(invalid_badges)
        })
    }
}
<|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.scoped::<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();
        tuples += lineitems.iter().map(|x| x.len()).sum();
        tuples += nations.iter().map(|x| x.len()).sum();
        tuples += orders.iter().map(|x| x.len()).sum();
        tuples += parts.iter().map(|x| x.len()).sum();
        tuples += partsupps.iter().map(|x| x.len()).sum();
        tuples += regions.iter().map(|x| x.len()).sum();
        tuples += suppliers.iter().map(|x| x.len()).sum();

        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() { inputs.0.send_batch(&mut data); }
            if let Some(mut data) = lineitems.pop() { 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() { 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 = 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();
            worker.step_while(|| probes.iter().all(|p| p.lt(&time)));
            round += 1;
        }

        let elapsed = timer.elapsed();
        let nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
        println!("elapsed: {:?}, tuples: {:?}, rate: {:?}", 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));
        }

        if count % 10000 == 0 {
            print!("\rreading records from {:?}: {:?}", name, count);
            ::std::io::stdout().flush().ok().expect("Could not flush stdout");
        }

        count += 1;

        line.clear();
    }
    println!("\rreading records from {:?}: {:?}", name, count);

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

    result.reverse();
    result
}
<commit_msg>tracking timely changes<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, 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();
        tuples += lineitems.iter().map(|x| x.len()).sum();
        tuples += nations.iter().map(|x| x.len()).sum();
        tuples += orders.iter().map(|x| x.len()).sum();
        tuples += parts.iter().map(|x| x.len()).sum();
        tuples += partsupps.iter().map(|x| x.len()).sum();
        tuples += regions.iter().map(|x| x.len()).sum();
        tuples += suppliers.iter().map(|x| x.len()).sum();

        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() { inputs.0.send_batch(&mut data); }
            if let Some(mut data) = lineitems.pop() { 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() { 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 = 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();
            worker.step_while(|| probes.iter().all(|p| p.lt(&time)));
            round += 1;
        }

        let elapsed = timer.elapsed();
        let nanos = elapsed.as_secs() * 1000000000 + elapsed.subsec_nanos() as u64;
        println!("elapsed: {:?}, tuples: {:?}, rate: {:?}", 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));
        }

        if count % 10000 == 0 {
            print!("\rreading records from {:?}: {:?}", name, count);
            ::std::io::stdout().flush().ok().expect("Could not flush stdout");
        }

        count += 1;

        line.clear();
    }
    println!("\rreading records from {:?}: {:?}", name, count);

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

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


<commit_before>use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64};
use std::{f32, f64};

/// Numbers which have upper and lower bounds
pub trait Bounded {
    // FIXME (#5527): These should be associated constants
    /// returns the smallest finite number this type can represent
    fn min_value() -> Self;
    /// returns the largest finite number this type can represent
    fn max_value() -> Self;
}

macro_rules! bounded_impl {
    ($t:ty, $min:expr, $max:expr) => {
        impl Bounded for $t {
            #[inline]
            fn min_value() -> $t { $min }

            #[inline]
            fn max_value() -> $t { $max }
        }
    }
}

bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8,    u8::MIN,    u8::MAX);
bounded_impl!(u16,   u16::MIN,   u16::MAX);
bounded_impl!(u32,   u32::MIN,   u32::MAX);
bounded_impl!(u64,   u64::MIN,   u64::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8,    i8::MIN,    i8::MAX);
bounded_impl!(i16,   i16::MIN,   i16::MAX);
bounded_impl!(i32,   i32::MIN,   i32::MAX);
bounded_impl!(i64,   i64::MIN,   i64::MAX);

bounded_impl!(f32, f32::MIN, f32::MAX);

macro_rules! for_each_tuple_ {
    ( $m:ident !! ) => (
        $m! { }
    );
    ( $m:ident !! $h:ident, $($t:ident,)* ) => (
        $m! { $h $($t)* }
        for_each_tuple_! { $m !! $($t,)* }
    );
}
macro_rules! for_each_tuple {
    ( $m:ident ) => (
        for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
    );
}

macro_rules! bounded_tuple {
    ( $($name:ident)* ) => (
        impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
            fn min_value() -> Self {
                ($($name::min_value(),)*)
            }
            fn max_value() -> Self {
                ($($name::max_value(),)*)
            }
        }
    );
}

for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
<commit_msg>traits: inline Bounded tuple methods<commit_after>use std::{usize, u8, u16, u32, u64};
use std::{isize, i8, i16, i32, i64};
use std::{f32, f64};

/// Numbers which have upper and lower bounds
pub trait Bounded {
    // FIXME (#5527): These should be associated constants
    /// returns the smallest finite number this type can represent
    fn min_value() -> Self;
    /// returns the largest finite number this type can represent
    fn max_value() -> Self;
}

macro_rules! bounded_impl {
    ($t:ty, $min:expr, $max:expr) => {
        impl Bounded for $t {
            #[inline]
            fn min_value() -> $t { $min }

            #[inline]
            fn max_value() -> $t { $max }
        }
    }
}

bounded_impl!(usize, usize::MIN, usize::MAX);
bounded_impl!(u8,    u8::MIN,    u8::MAX);
bounded_impl!(u16,   u16::MIN,   u16::MAX);
bounded_impl!(u32,   u32::MIN,   u32::MAX);
bounded_impl!(u64,   u64::MIN,   u64::MAX);

bounded_impl!(isize, isize::MIN, isize::MAX);
bounded_impl!(i8,    i8::MIN,    i8::MAX);
bounded_impl!(i16,   i16::MIN,   i16::MAX);
bounded_impl!(i32,   i32::MIN,   i32::MAX);
bounded_impl!(i64,   i64::MIN,   i64::MAX);

bounded_impl!(f32, f32::MIN, f32::MAX);

macro_rules! for_each_tuple_ {
    ( $m:ident !! ) => (
        $m! { }
    );
    ( $m:ident !! $h:ident, $($t:ident,)* ) => (
        $m! { $h $($t)* }
        for_each_tuple_! { $m !! $($t,)* }
    );
}
macro_rules! for_each_tuple {
    ( $m:ident ) => (
        for_each_tuple_! { $m !! A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, }
    );
}

macro_rules! bounded_tuple {
    ( $($name:ident)* ) => (
        impl<$($name: Bounded,)*> Bounded for ($($name,)*) {
            #[inline]
            fn min_value() -> Self {
                ($($name::min_value(),)*)
            }
            #[inline]
            fn max_value() -> Self {
                ($($name::max_value(),)*)
            }
        }
    );
}

for_each_tuple!(bounded_tuple);
bounded_impl!(f64, f64::MIN, f64::MAX);
<|endoftext|>


<commit_before>// Bitkeeper command line utilities.

use regex::Regex;
use Result;
use rsure::bk::{self, BkDir};
use rsure::SureTree;
use std::collections::HashSet;
use std::os::linux::fs::MetadataExt;
use std::path::Path;

pub fn new(path: &str) -> Result<()> {
    try!(ensure_dir(path));
    try!(bk::setup(path));
    Ok(())
}

/// The given path must name either a not-yet-existent directory, or be an
/// empty directory.  Ensure that is the case.
///
pub fn ensure_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let path = path.as_ref();

    if path.is_dir() {
        for ent in try!(path.read_dir()) {
            let ent = try!(ent);
            return Err(format!("Directory {:?} is not empty (contains {:?}",
                               path, ent.path()).into());
        }
        Ok(())
    } else if path.exists() {
        Err(format!("Path {:?} names something other than a directory", path).into())
    } else {
        Ok(())
    }
}

/// Import a bunch of files from `src` and include them in the bkdir.
pub fn import<P1: AsRef<Path>, P2: AsRef<Path>>(src: P1, dest: P2) -> Result<()> {
    let src = src.as_ref();
    let bkd = try!(BkDir::new(dest));

    let re = Regex::new(r"^([^-]+)-(.*)\.dat\.gz$").unwrap();

    let mut namedir = vec![];

    let present = try!(bkd.query());
    let present = present.iter().map(|p| (&p.name, &p.file)).collect::<HashSet<_>>();

    println!("Present: {:?}", present);
    for ent in try!(src.read_dir()) {
        let ent = try!(ent);
        let name = ent.file_name();
        let name = match name.to_str() {
            None => continue,
            Some(name) => name,
        };
        match re.captures(name) {
            None => continue,
            Some(cap) => {
                // println!("ent: {:?} name {:?}",
                //          cap.at(1).unwrap(),
                //          cap.at(2).unwrap());
                let mtime = try!(ent.metadata()).st_mtime();
                namedir.push(ImportNode {
                    mtime: mtime,
                    name: cap.at(2).unwrap().to_owned(),
                    file: cap.at(1).unwrap().to_owned(),
                });
            },
        }
    }
    namedir.sort();
    for node in namedir {
        if present.contains(&(&node.name, &node.file)) {
            continue;
        }
        let name = format!("{}-{}.dat.gz", node.file, node.name);
        println!("Importing: {:?}", name);
        let tree = try!(SureTree::load(&src.join(name)));
        try!(bkd.save(&tree, &node.file, &node.name));
    }
    Ok(())
}

#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
struct ImportNode {
    mtime: i64,
    name: String,
    file: String,
}
<commit_msg>bk: Print summary rather than all files<commit_after>// Bitkeeper command line utilities.

use regex::Regex;
use Result;
use rsure::bk::{self, BkDir};
use rsure::SureTree;
use std::collections::HashSet;
use std::os::linux::fs::MetadataExt;
use std::path::Path;

pub fn new(path: &str) -> Result<()> {
    try!(ensure_dir(path));
    try!(bk::setup(path));
    Ok(())
}

/// The given path must name either a not-yet-existent directory, or be an
/// empty directory.  Ensure that is the case.
///
pub fn ensure_dir<P: AsRef<Path>>(path: P) -> Result<()> {
    let path = path.as_ref();

    if path.is_dir() {
        for ent in try!(path.read_dir()) {
            let ent = try!(ent);
            return Err(format!("Directory {:?} is not empty (contains {:?}",
                               path, ent.path()).into());
        }
        Ok(())
    } else if path.exists() {
        Err(format!("Path {:?} names something other than a directory", path).into())
    } else {
        Ok(())
    }
}

/// Import a bunch of files from `src` and include them in the bkdir.
pub fn import<P1: AsRef<Path>, P2: AsRef<Path>>(src: P1, dest: P2) -> Result<()> {
    let src = src.as_ref();
    let bkd = try!(BkDir::new(dest));

    let re = Regex::new(r"^([^-]+)-(.*)\.dat\.gz$").unwrap();

    let mut namedir = vec![];

    let present = try!(bkd.query());
    let present = present.iter().map(|p| (&p.name, &p.file)).collect::<HashSet<_>>();

    println!("{} surefiles already present", present.len());
    for ent in try!(src.read_dir()) {
        let ent = try!(ent);
        let name = ent.file_name();
        let name = match name.to_str() {
            None => continue,
            Some(name) => name,
        };
        match re.captures(name) {
            None => continue,
            Some(cap) => {
                // println!("ent: {:?} name {:?}",
                //          cap.at(1).unwrap(),
                //          cap.at(2).unwrap());
                let mtime = try!(ent.metadata()).st_mtime();
                namedir.push(ImportNode {
                    mtime: mtime,
                    name: cap.at(2).unwrap().to_owned(),
                    file: cap.at(1).unwrap().to_owned(),
                });
            },
        }
    }
    namedir.sort();
    for node in namedir {
        if present.contains(&(&node.name, &node.file)) {
            continue;
        }
        let name = format!("{}-{}.dat.gz", node.file, node.name);
        println!("Importing: {:?}", name);
        let tree = try!(SureTree::load(&src.join(name)));
        try!(bkd.save(&tree, &node.file, &node.name));
    }
    Ok(())
}

#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
struct ImportNode {
    mtime: i64,
    name: String,
    file: String,
}
<|endoftext|>


<commit_before>use color::Color;
use game::Piece;

#[derive(Debug, PartialEq, Eq)]
pub struct Board {
    color_matrix: Vec<Vec<Option<Color>>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Board {
        Board {
            color_matrix: vec![vec![None; width]; height],
        }
    }

    fn height(&self) -> usize {
        self.color_matrix.len()
    }

    fn width(&self) -> usize {
        self.color_matrix.get(0).unwrap_or(&vec![]).len()
    }

    pub fn set(&mut self, row: usize, col: usize, color: Color) {
        self.color_matrix.get_mut(row).unwrap()[col] = Some(color);
    }

    pub fn get(&self, row: usize, col:usize) -> Option<Color> {
        self.color_matrix.get(row)
            .unwrap_or(&vec![])
            .get(col)
            .unwrap_or(&None)
            .clone()
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.color_matrix.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .collect()
    }

    fn get_sequential_pieces(&self, coordinates: Vec<(usize, usize)>) -> Vec<Piece> {
        let mut sequence_coordinates: Vec<&(usize, usize)> = coordinates.windows(4)
            .filter(|sequence| {
                sequence.get(0).map_or(false, |&(row_0, col_0)| {
                    self.get(row_0, col_0).map_or(false, |first_color| {
                        sequence.iter().all(|&(row, col)| {
                            self.get(row, col) == Some(first_color.clone())
                        })
                    })
                })
            })
            .flat_map(|s| s)
            .collect();

            sequence_coordinates.sort();
            sequence_coordinates.dedup();

            sequence_coordinates.iter().map(|&&(row, col)| {
                Piece { row: row, col: col, color: self.get(row, col).unwrap() }
            }).collect()
    }

    pub fn get_pieces_to_clear(&self) -> Vec<Piece> {
        let mut pieces: Vec<Piece> = vec![];

        // vertical
        for col in 0..self.width() {
            let mut coordinates = vec![];

            for row in 0..self.height() {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // horizontal
        for row in 0..self.height() {
            let mut coordinates = vec![];

            for col in 0..self.width() {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal up by row, looks like /
        for starting_row in 0..self.height() {
            let mut coordinates = vec![];

            for (row, col) in (0...starting_row).rev().zip(0..self.width()) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal up by col, looks like /
        for starting_col in 1..self.width() {
            let mut coordinates = vec![];

            for (row, col) in (0..self.height()).rev().zip(starting_col..self.width()) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal down by row, looks like \
        for starting_row in 0..self.height() {
            let mut coordinates = vec![];

            for (row, col) in (starting_row..self.height()).zip(0..self.width()) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        pieces
    }

    pub fn clear_all(&mut self, pieces: Vec<Piece>) {
    }

    pub fn get_lowest_free_row_in_col(&self, col: usize) -> usize {
        self.color_matrix.iter()
            .rposition(|row| row.get(col).unwrap_or(&None).is_none())
            .unwrap()
    }
}

#[cfg(test)]
mod tests {
    use board::Board;
    use color::Color::*;
    use game::Piece;

    #[test]
    fn get_pieces_to_clear_diagonal_down() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red) ],
                vec![ None, None, Some(Red), None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ Some(Red), None, None, None, None ],
                vec![ None, None, None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, None, None, None, Some(Red) ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 4, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
            Piece { row: 1, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_horizontal() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
                vec![ None, None, None, None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Yellow), None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 3, col: 0, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical_none_eligible() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Blue), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
            ],
        };

        let expected_pieces_to_clear: Vec<Piece> = vec![];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn set_a_color() {
        let mut board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Red) ],
            ],
        };

        board.set(1, 1, Yellow);

        let expected_board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_a_color() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Blue) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        let color = board.get(0, 1);

        let expected_color = Some(Blue);

        assert_eq!(expected_color, color);
    }

    #[test]
    fn get_lowest_free_row_in_col() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ None, None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 1;

        assert_eq!(expected_row, row);
    }

    #[test]
    fn get_lowest_free_row_in_col_with_another_existing_piece() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ Some(Red), None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 0;

        assert_eq!(expected_row, row);
    }
}
<commit_msg>clear diagonal down<commit_after>use color::Color;
use game::Piece;

#[derive(Debug, PartialEq, Eq)]
pub struct Board {
    color_matrix: Vec<Vec<Option<Color>>>,
}

impl Board {
    pub fn new(width: usize, height: usize) -> Board {
        Board {
            color_matrix: vec![vec![None; width]; height],
        }
    }

    fn height(&self) -> usize {
        self.color_matrix.len()
    }

    fn width(&self) -> usize {
        self.color_matrix.get(0).unwrap_or(&vec![]).len()
    }

    pub fn set(&mut self, row: usize, col: usize, color: Color) {
        self.color_matrix.get_mut(row).unwrap()[col] = Some(color);
    }

    pub fn get(&self, row: usize, col:usize) -> Option<Color> {
        self.color_matrix.get(row)
            .unwrap_or(&vec![])
            .get(col)
            .unwrap_or(&None)
            .clone()
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.color_matrix.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .collect()
    }

    fn get_sequential_pieces(&self, coordinates: Vec<(usize, usize)>) -> Vec<Piece> {
        let mut sequence_coordinates: Vec<&(usize, usize)> = coordinates.windows(4)
            .filter(|sequence| {
                sequence.get(0).map_or(false, |&(row_0, col_0)| {
                    self.get(row_0, col_0).map_or(false, |first_color| {
                        sequence.iter().all(|&(row, col)| {
                            self.get(row, col) == Some(first_color.clone())
                        })
                    })
                })
            })
            .flat_map(|s| s)
            .collect();

            sequence_coordinates.sort();
            sequence_coordinates.dedup();

            sequence_coordinates.iter().map(|&&(row, col)| {
                Piece { row: row, col: col, color: self.get(row, col).unwrap() }
            }).collect()
    }

    pub fn get_pieces_to_clear(&self) -> Vec<Piece> {
        let mut pieces: Vec<Piece> = vec![];

        // vertical
        for col in 0..self.width() {
            let mut coordinates = vec![];

            for row in 0..self.height() {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // horizontal
        for row in 0..self.height() {
            let mut coordinates = vec![];

            for col in 0..self.width() {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal up by row, looks like /
        for starting_row in 0..self.height() {
            let mut coordinates = vec![];

            for (row, col) in (0...starting_row).rev().zip(0..self.width()) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal up by col, looks like /
        for starting_col in 1..self.width() {
            let mut coordinates = vec![];

            for (row, col) in (0..self.height()).rev().zip(starting_col..self.width()) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal down by row, looks like \
        for starting_row in 0..self.height() {
            let mut coordinates = vec![];

            for (row, col) in (starting_row..self.height()).zip(0..self.width()) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        // diagonal down by col, looks like \
        for starting_col in 1..self.width() {
            let mut coordinates = vec![];

            for (row, col) in (0..self.height()).zip((starting_col..self.width())) {
                coordinates.push((row, col));
            }

            let new_pieces = self.get_sequential_pieces(coordinates);

            for s in new_pieces {
                pieces.push(s);
            }
        }

        pieces
    }

    pub fn clear_all(&mut self, pieces: Vec<Piece>) {
    }

    pub fn get_lowest_free_row_in_col(&self, col: usize) -> usize {
        self.color_matrix.iter()
            .rposition(|row| row.get(col).unwrap_or(&None).is_none())
            .unwrap()
    }
}

#[cfg(test)]
mod tests {
    use board::Board;
    use color::Color::*;
    use game::Piece;

    #[test]
    fn get_pieces_to_clear_diagonal_down() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None],
                vec![ Some(Red), None, None, None ],
                vec![ None, Some(Red), None, None ],
                vec![ None, None, Some(Red), None ],
                vec![ None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 4, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_down_off_center_right() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, None, None, Some(Red) ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 1, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 3, col: 3, color: Red },
            Piece { row: 4, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red) ],
                vec![ None, None, Some(Red), None ],
                vec![ None, Some(Red), None, None ],
                vec![ Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_up() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
                vec![ Some(Red), None, None, None, None ],
                vec![ None, None, None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 3, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 1, col: 2, color: Red },
            Piece { row: 0, col: 3, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_diagonal_up_off_center_down() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None, None ],
                vec![ None, None, None, None, Some(Red) ],
                vec![ None, None, None, Some(Red), None ],
                vec![ None, None, Some(Red), None, None ],
                vec![ None, Some(Red), None, None, None ],
            ],
        };

        let mut expected_pieces_to_clear = vec![
            Piece { row: 4, col: 1, color: Red },
            Piece { row: 3, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
            Piece { row: 1, col: 4, color: Red },
        ];

        let mut pieces_to_clear = board.get_pieces_to_clear();

        expected_pieces_to_clear.sort();
        pieces_to_clear.sort();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_horizontal() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None, None, None ],
                vec![ None, None, None, None ],
                vec![ Some(Red), Some(Red), Some(Red), Some(Red) ],
                vec![ None, None, None, None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 2, col: 1, color: Red },
            Piece { row: 2, col: 2, color: Red },
            Piece { row: 2, col: 3, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
                vec![ Some(Yellow), None ],
            ],
        };

        let expected_pieces_to_clear = vec![
            Piece { row: 0, col: 0, color: Red },
            Piece { row: 1, col: 0, color: Red },
            Piece { row: 2, col: 0, color: Red },
            Piece { row: 3, col: 0, color: Red },
        ];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn get_pieces_to_clear_vertical_none_eligible() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), None ],
                vec![ Some(Blue), None ],
                vec![ Some(Red), None ],
                vec![ Some(Red), None ],
            ],
        };

        let expected_pieces_to_clear: Vec<Piece> = vec![];

        let pieces_to_clear = board.get_pieces_to_clear();

        assert_eq!(expected_pieces_to_clear, pieces_to_clear);
    }

    #[test]
    fn set_a_color() {
        let mut board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Red) ],
            ],
        };

        board.set(1, 1, Yellow);

        let expected_board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Red) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        assert_eq!(expected_board, board);
    }

    #[test]
    fn get_a_color() {
        let board = Board {
            color_matrix: vec![
                vec![ Some(Red), Some(Blue) ],
                vec![ Some(Red), Some(Yellow) ],
            ],
        };

        let color = board.get(0, 1);

        let expected_color = Some(Blue);

        assert_eq!(expected_color, color);
    }

    #[test]
    fn get_lowest_free_row_in_col() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ None, None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 1;

        assert_eq!(expected_row, row);
    }

    #[test]
    fn get_lowest_free_row_in_col_with_another_existing_piece() {
        let board = Board {
            color_matrix: vec![
                vec![ None, None ],
                vec![ Some(Red), None ],
            ],
        };

        let row = board.get_lowest_free_row_in_col(0);
        let expected_row = 0;

        assert_eq!(expected_row, row);
    }
}
<|endoftext|>