<commit_before>use gtk::widgets;
use rustc_serialize::{Encodable, json};
use std::cell::Cell;
use std::env;
use std::collections::{HashMap, HashSet};
use std::io::{Read, Write};
use std::fs::{self, PathExt};
use std::ops::Deref;
use std::path::{Path, PathBuf};

pub static WINDOW_WIDTH : i32 = 1242;
pub static WINDOW_HEIGHT : i32 = 768;
pub static EDITOR_HEIGHT_PCT : f32 = 0.70;
pub static MIN_FONT_SIZE : i32 = 0;
pub static MAX_FONT_SIZE : i32 = 50;

#[cfg(target_os = "macos")]
pub static META_KEY : u32 = 1 << 28;
#[cfg(not(target_os = "macos"))]
pub static META_KEY : u32 = 1 << 2;

pub static DATA_DIR : &'static str = ".soak";
pub static CONFIG_FILE : &'static str = ".soakrc";
pub static CONFIG_CONTENT : &'static str = include_str!("../resources/soakrc");
pub static PREFS_FILE : &'static str = "prefs.json";
pub static SETTINGS_FILE : &'static str = "settings.json";
pub static NO_WINDOW_FLAG : &'static str = "-nw";

pub struct Resource {
    pub path: &'static [&'static str],
    pub data: &'static str,
    pub always_copy: bool
}
pub static DATA_CONTENT : &'static [Resource] = &[
    Resource{path: &["after", "syntax", "rust.vim"],
             data: include_str!("../resources/soak/after/syntax/rust.vim"),
             always_copy: true},

    Resource{path: &["autoload", "paste.vim"],
             data: include_str!("../resources/soak/autoload/paste.vim"),
             always_copy: false},
    Resource{path: &["autoload", "rust.vim"],
             data: include_str!("../resources/soak/autoload/rust.vim"),
             always_copy: true},

    Resource{path: &["compiler", "rustc.vim"],
             data: include_str!("../resources/soak/compiler/rustc.vim"),
             always_copy: true},
    Resource{path: &["compiler", "cargo.vim"],
             data: include_str!("../resources/soak/compiler/cargo.vim"),
             always_copy: true},

    Resource{path: &["doc", "rust.txt"],
             data: include_str!("../resources/soak/doc/rust.txt"),
             always_copy: true},

    Resource{path: &["ftdetect", "rust.vim"],
             data: include_str!("../resources/soak/ftdetect/rust.vim"),
             always_copy: true},

    Resource{path: &["ftplugin", "rust.vim"],
             data: include_str!("../resources/soak/ftplugin/rust.vim"),
             always_copy: true},
    Resource{path: &["ftplugin", "c.vim"],
             data: include_str!("../resources/soak/ftplugin/c.vim"),
             always_copy: false},

    Resource{path: &["indent", "rust.vim"],
             data: include_str!("../resources/soak/indent/rust.vim"),
             always_copy: true},
    Resource{path: &["indent", "c.vim"],
             data: include_str!("../resources/soak/indent/c.vim"),
             always_copy: false},

    Resource{path: &["plugin", "eunuch.vim"],
             data: include_str!("../resources/soak/plugin/eunuch.vim"),
             always_copy: false},
    Resource{path: &["plugin", "racer.vim"],
             data: include_str!("../resources/soak/plugin/racer.vim"),
             always_copy: true},
    Resource{path: &["plugin", "rust.vim"],
             data: include_str!("../resources/soak/plugin/rust.vim"),
             always_copy: true},

    Resource{path: &["syntax", "c.vim"],
             data: include_str!("../resources/soak/syntax/c.vim"),
             always_copy: false},
    Resource{path: &["syntax", "nosyntax.vim"],
             data: include_str!("../resources/soak/syntax/nosyntax.vim"),
             always_copy: false},
    Resource{path: &["syntax", "rust.vim"],
             data: include_str!("../resources/soak/syntax/rust.vim"),
             always_copy: true},
    Resource{path: &["syntax", "syncolor.vim"],
             data: include_str!("../resources/soak/syntax/syncolor.vim"),
             always_copy: false},
    Resource{path: &["syntax", "synload.vim"],
             data: include_str!("../resources/soak/syntax/synload.vim"),
             always_copy: false},
    Resource{path: &["syntax", "syntax.vim"],
             data: include_str!("../resources/soak/syntax/syntax.vim"),
             always_copy: false},

    Resource{path: &["syntax_checkers", "rust", "rustc.vim"],
             data: include_str!("../resources/soak/syntax_checkers/rust/rustc.vim"),
             always_copy: true},

    Resource{path: &["filetype.vim"],
             data: include_str!("../resources/soak/filetype.vim"),
             always_copy: false}
];

pub struct State<'a> {
    pub projects: HashSet<String>,
    pub expansions: HashSet<String>,
    pub selection: Option<String>,
    pub easy_mode: bool,
    pub font_size: i32,
    pub builders: HashMap<PathBuf, (widgets::VteTerminal, Cell<i32>)>,
    pub window: &'a widgets::Window,
    pub tree_store: &'a widgets::TreeStore,
    pub tree_model: &'a widgets::TreeModel,
    pub tree_selection: &'a widgets::TreeSelection,
    pub rename_button: &'a widgets::Button,
    pub remove_button: &'a widgets::Button,
    pub is_refreshing_tree: bool
}

#[derive(RustcDecodable, RustcEncodable)]
struct Prefs {
    projects: Vec<String>,
    expansions: Vec<String>,
    selection: Option<String>,
    easy_mode: bool,
    font_size: i32
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct KeySettings {
    pub new_project: Option<String>,
    pub import: Option<String>,
    pub rename: Option<String>,
    pub remove: Option<String>,

    pub run: Option<String>,
    pub build: Option<String>,
    pub test: Option<String>,
    pub clean: Option<String>,
    pub stop: Option<String>,

    pub save: Option<String>,
    pub undo: Option<String>,
    pub redo: Option<String>,
    pub font_dec: Option<String>,
    pub font_inc: Option<String>,
    pub close: Option<String>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct Settings {
    pub keys: KeySettings
}

pub fn get_home_dir() -> PathBuf {
    if let Some(path) = env::home_dir() {
        path
    } else {
        PathBuf::from(".")
    }
}

fn get_prefs(state: &State) -> Prefs {
    Prefs {
        projects: state.projects.clone().into_iter().collect(),
        expansions: state.expansions.clone().into_iter().collect(),
        selection: state.selection.clone(),
        easy_mode: state.easy_mode,
        font_size: state.font_size
    }
}

pub fn is_parent_path(parent_str: &String, child_str: &String) -> bool {
    let parent_ref: &str = parent_str.as_ref();
    child_str.starts_with(parent_ref) &&
    Path::new(parent_str).parent() != Path::new(child_str).parent()
}

pub fn get_selected_path(state: &State) -> Option<String> {
    let mut iter = widgets::TreeIter::new().unwrap();

    if state.tree_selection.get_selected(state.tree_model, &mut iter) {
        state.tree_model.get_value(&iter, 1).get_string()
    } else {
        None
    }
}

fn is_project_path(path: &Path) -> bool {
    path.join("Cargo.toml").exists()
}

fn is_project_root(state: &State, path: &Path) -> bool {
    if let Some(path_str) = path.to_str() {
        state.projects.contains(&path_str.to_string())
    } else {
        false
    }
}

pub fn get_project_path(state: &State, path: &Path) -> Option<PathBuf> {
    if is_project_path(path) || is_project_root(state, path) {
        Some(PathBuf::from(path))
    } else {
        if let Some(parent_path) = path.parent() {
            get_project_path(state, parent_path.deref())
        } else {
            None
        }
    }
}

pub fn get_selected_project_path(state: &State) -> Option<PathBuf> {
    if let Some(path_str) = get_selected_path(state) {
        get_project_path(state, Path::new(&path_str))
    } else {
        None
    }
}

pub fn write_prefs(state: &State) {
    let prefs = get_prefs(state);

    let mut json_str = String::new();
    {
        let mut encoder = json::Encoder::new_pretty(&mut json_str);
        prefs.encode(&mut encoder).ok().expect("Error encoding prefs.");
    }

    let prefs_path = get_home_dir().deref().join(DATA_DIR).join(PREFS_FILE);
    if let Some(mut f) = fs::File::create(&prefs_path).ok() {
        match f.write(json_str.as_bytes()) {
            Ok(_) => {},
            Err(e) => println!("Error writing prefs: {}", e)
        };
    }
}

pub fn read_prefs(state: &mut State) {
    let prefs_path = get_home_dir().deref().join(DATA_DIR).join(PREFS_FILE);
    if let Some(mut f) = fs::File::open(&prefs_path).ok() {
        let mut json_str = String::new();
        let prefs_option : Option<Prefs> = match f.read_to_string(&mut json_str) {
            Ok(_) => {
                match json::decode(json_str.as_ref()) {
                    Ok(object) => Some(object),
                    Err(e) => {
                        println!("Error decoding prefs: {}", e);
                        None
                    }
                }
            },
            Err(_) => None
        };

        if let Some(prefs) = prefs_option {
            state.projects.clear();
            for path_str in prefs.projects.iter() {
                state.projects.insert(path_str.clone());
            }

            state.expansions.clear();
            for path_str in prefs.expansions.iter() {
                state.expansions.insert(path_str.clone());
            }

            state.selection = prefs.selection;
            state.easy_mode = prefs.easy_mode;

            if (prefs.font_size >= MIN_FONT_SIZE) && (prefs.font_size <= MAX_FONT_SIZE) {
                state.font_size = prefs.font_size;
            }
        }
    }
}

fn get_settings() -> Settings {
    Settings {
        keys: ::utils::KeySettings {
            new_project: Some("p".to_string()),
            import: Some("o".to_string()),
            rename: Some("n".to_string()),
            remove: Some("g".to_string()),

            run: Some("a".to_string()),
            build: Some("k".to_string()),
            test: Some("t".to_string()),
            clean: Some("l".to_string()),
            stop: Some("i".to_string()),

            save: Some("s".to_string()),
            undo: Some("z".to_string()),
            redo: Some("r".to_string()),
            font_dec: Some("minus".to_string()),
            font_inc: Some("equal".to_string()),
            close: Some("w".to_string())
        }
    }
}

pub fn write_settings() {
    let settings_path = get_home_dir().deref().join(DATA_DIR).join(SETTINGS_FILE);
    if settings_path.exists() { // don't overwrite existing file, so user can modify it
        return;
    }

    let default_settings = get_settings();

    let mut json_str = String::new();
    {
        let mut encoder = json::Encoder::new_pretty(&mut json_str);
        default_settings.encode(&mut encoder).ok().expect("Error encoding settings.");
    }

    if let Some(mut f) = fs::File::create(&settings_path).ok() {
        match f.write(json_str.as_bytes()) {
            Ok(_) => {},
            Err(e) => println!("Error writing settings: {}", e)
        };
    }
}

pub fn read_settings() -> Settings {
    let default_settings = get_settings();
    let settings_path = get_home_dir().deref().join(DATA_DIR).join(SETTINGS_FILE);

    if let Some(mut f) = fs::File::open(&settings_path).ok() {
        let mut json_str = String::new();
        let settings_opt : Option<Settings> = match f.read_to_string(&mut json_str) {
            Ok(_) => {
                match json::decode(json_str.as_ref()) {
                    Ok(object) => Some(object),
                    Err(e) => {
                        println!("Error decoding settings: {}", e);
                        None
                    }
                }
            },
            Err(_) => None
        };

        if let Some(mut settings) = settings_opt {
            let keys = default_settings.keys;

            if let Some(key) = keys.new_project {
                settings.keys.new_project = Some(settings.keys.new_project.unwrap_or(key));
            }
            if let Some(key) = keys.import {
                settings.keys.import = Some(settings.keys.import.unwrap_or(key));
            }
            if let Some(key) = keys.rename {
                settings.keys.rename = Some(settings.keys.rename.unwrap_or(key));
            }
            if let Some(key) = keys.remove {
                settings.keys.remove = Some(settings.keys.remove.unwrap_or(key));
            }

            if let Some(key) = keys.run {
                settings.keys.run = Some(settings.keys.run.unwrap_or(key));
            }
            if let Some(key) = keys.build {
                settings.keys.build = Some(settings.keys.build.unwrap_or(key));
            }
            if let Some(key) = keys.test {
                settings.keys.test = Some(settings.keys.test.unwrap_or(key));
            }
            if let Some(key) = keys.clean {
                settings.keys.clean = Some(settings.keys.clean.unwrap_or(key));
            }
            if let Some(key) = keys.stop {
                settings.keys.stop = Some(settings.keys.stop.unwrap_or(key))
            }

            if let Some(key) = keys.save {
                settings.keys.save = Some(settings.keys.save.unwrap_or(key));
            }
            if let Some(key) = keys.undo {
                settings.keys.undo = Some(settings.keys.undo.unwrap_or(key));
            }
            if let Some(key) = keys.redo {
                settings.keys.redo = Some(settings.keys.redo.unwrap_or(key));
            }
            if let Some(key) = keys.font_dec {
                settings.keys.font_dec = Some(settings.keys.font_dec.unwrap_or(key));
            }
            if let Some(key) = keys.font_inc {
                settings.keys.font_inc = Some(settings.keys.font_inc.unwrap_or(key));
            }
            if let Some(key) = keys.close {
                settings.keys.close = Some(settings.keys.close.unwrap_or(key));
            }

            return settings;
        }
    }

    default_settings
}
<commit_msg>Don't use o as a shortcut<commit_after>use gtk::widgets;
use rustc_serialize::{Encodable, json};
use std::cell::Cell;
use std::env;
use std::collections::{HashMap, HashSet};
use std::io::{Read, Write};
use std::fs::{self, PathExt};
use std::ops::Deref;
use std::path::{Path, PathBuf};

pub static WINDOW_WIDTH : i32 = 1242;
pub static WINDOW_HEIGHT : i32 = 768;
pub static EDITOR_HEIGHT_PCT : f32 = 0.70;
pub static MIN_FONT_SIZE : i32 = 0;
pub static MAX_FONT_SIZE : i32 = 50;

#[cfg(target_os = "macos")]
pub static META_KEY : u32 = 1 << 28;
#[cfg(not(target_os = "macos"))]
pub static META_KEY : u32 = 1 << 2;

pub static DATA_DIR : &'static str = ".soak";
pub static CONFIG_FILE : &'static str = ".soakrc";
pub static CONFIG_CONTENT : &'static str = include_str!("../resources/soakrc");
pub static PREFS_FILE : &'static str = "prefs.json";
pub static SETTINGS_FILE : &'static str = "settings.json";
pub static NO_WINDOW_FLAG : &'static str = "-nw";

pub struct Resource {
    pub path: &'static [&'static str],
    pub data: &'static str,
    pub always_copy: bool
}
pub static DATA_CONTENT : &'static [Resource] = &[
    Resource{path: &["after", "syntax", "rust.vim"],
             data: include_str!("../resources/soak/after/syntax/rust.vim"),
             always_copy: true},

    Resource{path: &["autoload", "paste.vim"],
             data: include_str!("../resources/soak/autoload/paste.vim"),
             always_copy: false},
    Resource{path: &["autoload", "rust.vim"],
             data: include_str!("../resources/soak/autoload/rust.vim"),
             always_copy: true},

    Resource{path: &["compiler", "rustc.vim"],
             data: include_str!("../resources/soak/compiler/rustc.vim"),
             always_copy: true},
    Resource{path: &["compiler", "cargo.vim"],
             data: include_str!("../resources/soak/compiler/cargo.vim"),
             always_copy: true},

    Resource{path: &["doc", "rust.txt"],
             data: include_str!("../resources/soak/doc/rust.txt"),
             always_copy: true},

    Resource{path: &["ftdetect", "rust.vim"],
             data: include_str!("../resources/soak/ftdetect/rust.vim"),
             always_copy: true},

    Resource{path: &["ftplugin", "rust.vim"],
             data: include_str!("../resources/soak/ftplugin/rust.vim"),
             always_copy: true},
    Resource{path: &["ftplugin", "c.vim"],
             data: include_str!("../resources/soak/ftplugin/c.vim"),
             always_copy: false},

    Resource{path: &["indent", "rust.vim"],
             data: include_str!("../resources/soak/indent/rust.vim"),
             always_copy: true},
    Resource{path: &["indent", "c.vim"],
             data: include_str!("../resources/soak/indent/c.vim"),
             always_copy: false},

    Resource{path: &["plugin", "eunuch.vim"],
             data: include_str!("../resources/soak/plugin/eunuch.vim"),
             always_copy: false},
    Resource{path: &["plugin", "racer.vim"],
             data: include_str!("../resources/soak/plugin/racer.vim"),
             always_copy: true},
    Resource{path: &["plugin", "rust.vim"],
             data: include_str!("../resources/soak/plugin/rust.vim"),
             always_copy: true},

    Resource{path: &["syntax", "c.vim"],
             data: include_str!("../resources/soak/syntax/c.vim"),
             always_copy: false},
    Resource{path: &["syntax", "nosyntax.vim"],
             data: include_str!("../resources/soak/syntax/nosyntax.vim"),
             always_copy: false},
    Resource{path: &["syntax", "rust.vim"],
             data: include_str!("../resources/soak/syntax/rust.vim"),
             always_copy: true},
    Resource{path: &["syntax", "syncolor.vim"],
             data: include_str!("../resources/soak/syntax/syncolor.vim"),
             always_copy: false},
    Resource{path: &["syntax", "synload.vim"],
             data: include_str!("../resources/soak/syntax/synload.vim"),
             always_copy: false},
    Resource{path: &["syntax", "syntax.vim"],
             data: include_str!("../resources/soak/syntax/syntax.vim"),
             always_copy: false},

    Resource{path: &["syntax_checkers", "rust", "rustc.vim"],
             data: include_str!("../resources/soak/syntax_checkers/rust/rustc.vim"),
             always_copy: true},

    Resource{path: &["filetype.vim"],
             data: include_str!("../resources/soak/filetype.vim"),
             always_copy: false}
];

pub struct State<'a> {
    pub projects: HashSet<String>,
    pub expansions: HashSet<String>,
    pub selection: Option<String>,
    pub easy_mode: bool,
    pub font_size: i32,
    pub builders: HashMap<PathBuf, (widgets::VteTerminal, Cell<i32>)>,
    pub window: &'a widgets::Window,
    pub tree_store: &'a widgets::TreeStore,
    pub tree_model: &'a widgets::TreeModel,
    pub tree_selection: &'a widgets::TreeSelection,
    pub rename_button: &'a widgets::Button,
    pub remove_button: &'a widgets::Button,
    pub is_refreshing_tree: bool
}

#[derive(RustcDecodable, RustcEncodable)]
struct Prefs {
    projects: Vec<String>,
    expansions: Vec<String>,
    selection: Option<String>,
    easy_mode: bool,
    font_size: i32
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct KeySettings {
    pub new_project: Option<String>,
    pub import: Option<String>,
    pub rename: Option<String>,
    pub remove: Option<String>,

    pub run: Option<String>,
    pub build: Option<String>,
    pub test: Option<String>,
    pub clean: Option<String>,
    pub stop: Option<String>,

    pub save: Option<String>,
    pub undo: Option<String>,
    pub redo: Option<String>,
    pub font_dec: Option<String>,
    pub font_inc: Option<String>,
    pub close: Option<String>
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct Settings {
    pub keys: KeySettings
}

pub fn get_home_dir() -> PathBuf {
    if let Some(path) = env::home_dir() {
        path
    } else {
        PathBuf::from(".")
    }
}

fn get_prefs(state: &State) -> Prefs {
    Prefs {
        projects: state.projects.clone().into_iter().collect(),
        expansions: state.expansions.clone().into_iter().collect(),
        selection: state.selection.clone(),
        easy_mode: state.easy_mode,
        font_size: state.font_size
    }
}

pub fn is_parent_path(parent_str: &String, child_str: &String) -> bool {
    let parent_ref: &str = parent_str.as_ref();
    child_str.starts_with(parent_ref) &&
    Path::new(parent_str).parent() != Path::new(child_str).parent()
}

pub fn get_selected_path(state: &State) -> Option<String> {
    let mut iter = widgets::TreeIter::new().unwrap();

    if state.tree_selection.get_selected(state.tree_model, &mut iter) {
        state.tree_model.get_value(&iter, 1).get_string()
    } else {
        None
    }
}

fn is_project_path(path: &Path) -> bool {
    path.join("Cargo.toml").exists()
}

fn is_project_root(state: &State, path: &Path) -> bool {
    if let Some(path_str) = path.to_str() {
        state.projects.contains(&path_str.to_string())
    } else {
        false
    }
}

pub fn get_project_path(state: &State, path: &Path) -> Option<PathBuf> {
    if is_project_path(path) || is_project_root(state, path) {
        Some(PathBuf::from(path))
    } else {
        if let Some(parent_path) = path.parent() {
            get_project_path(state, parent_path.deref())
        } else {
            None
        }
    }
}

pub fn get_selected_project_path(state: &State) -> Option<PathBuf> {
    if let Some(path_str) = get_selected_path(state) {
        get_project_path(state, Path::new(&path_str))
    } else {
        None
    }
}

pub fn write_prefs(state: &State) {
    let prefs = get_prefs(state);

    let mut json_str = String::new();
    {
        let mut encoder = json::Encoder::new_pretty(&mut json_str);
        prefs.encode(&mut encoder).ok().expect("Error encoding prefs.");
    }

    let prefs_path = get_home_dir().deref().join(DATA_DIR).join(PREFS_FILE);
    if let Some(mut f) = fs::File::create(&prefs_path).ok() {
        match f.write(json_str.as_bytes()) {
            Ok(_) => {},
            Err(e) => println!("Error writing prefs: {}", e)
        };
    }
}

pub fn read_prefs(state: &mut State) {
    let prefs_path = get_home_dir().deref().join(DATA_DIR).join(PREFS_FILE);
    if let Some(mut f) = fs::File::open(&prefs_path).ok() {
        let mut json_str = String::new();
        let prefs_option : Option<Prefs> = match f.read_to_string(&mut json_str) {
            Ok(_) => {
                match json::decode(json_str.as_ref()) {
                    Ok(object) => Some(object),
                    Err(e) => {
                        println!("Error decoding prefs: {}", e);
                        None
                    }
                }
            },
            Err(_) => None
        };

        if let Some(prefs) = prefs_option {
            state.projects.clear();
            for path_str in prefs.projects.iter() {
                state.projects.insert(path_str.clone());
            }

            state.expansions.clear();
            for path_str in prefs.expansions.iter() {
                state.expansions.insert(path_str.clone());
            }

            state.selection = prefs.selection;
            state.easy_mode = prefs.easy_mode;

            if (prefs.font_size >= MIN_FONT_SIZE) && (prefs.font_size <= MAX_FONT_SIZE) {
                state.font_size = prefs.font_size;
            }
        }
    }
}

fn get_settings() -> Settings {
    Settings {
        keys: ::utils::KeySettings {
            new_project: Some("p".to_string()),
            import: Some("i".to_string()),
            rename: Some("n".to_string()),
            remove: Some("g".to_string()),

            run: Some("a".to_string()),
            build: Some("k".to_string()),
            test: Some("t".to_string()),
            clean: Some("l".to_string()),
            stop: Some("h".to_string()),

            save: Some("s".to_string()),
            undo: Some("z".to_string()),
            redo: Some("r".to_string()),
            font_dec: Some("minus".to_string()),
            font_inc: Some("equal".to_string()),
            close: Some("w".to_string())
        }
    }
}

pub fn write_settings() {
    let settings_path = get_home_dir().deref().join(DATA_DIR).join(SETTINGS_FILE);
    if settings_path.exists() { // don't overwrite existing file, so user can modify it
        return;
    }

    let default_settings = get_settings();

    let mut json_str = String::new();
    {
        let mut encoder = json::Encoder::new_pretty(&mut json_str);
        default_settings.encode(&mut encoder).ok().expect("Error encoding settings.");
    }

    if let Some(mut f) = fs::File::create(&settings_path).ok() {
        match f.write(json_str.as_bytes()) {
            Ok(_) => {},
            Err(e) => println!("Error writing settings: {}", e)
        };
    }
}

pub fn read_settings() -> Settings {
    let default_settings = get_settings();
    let settings_path = get_home_dir().deref().join(DATA_DIR).join(SETTINGS_FILE);

    if let Some(mut f) = fs::File::open(&settings_path).ok() {
        let mut json_str = String::new();
        let settings_opt : Option<Settings> = match f.read_to_string(&mut json_str) {
            Ok(_) => {
                match json::decode(json_str.as_ref()) {
                    Ok(object) => Some(object),
                    Err(e) => {
                        println!("Error decoding settings: {}", e);
                        None
                    }
                }
            },
            Err(_) => None
        };

        if let Some(mut settings) = settings_opt {
            let keys = default_settings.keys;

            if let Some(key) = keys.new_project {
                settings.keys.new_project = Some(settings.keys.new_project.unwrap_or(key));
            }
            if let Some(key) = keys.import {
                settings.keys.import = Some(settings.keys.import.unwrap_or(key));
            }
            if let Some(key) = keys.rename {
                settings.keys.rename = Some(settings.keys.rename.unwrap_or(key));
            }
            if let Some(key) = keys.remove {
                settings.keys.remove = Some(settings.keys.remove.unwrap_or(key));
            }

            if let Some(key) = keys.run {
                settings.keys.run = Some(settings.keys.run.unwrap_or(key));
            }
            if let Some(key) = keys.build {
                settings.keys.build = Some(settings.keys.build.unwrap_or(key));
            }
            if let Some(key) = keys.test {
                settings.keys.test = Some(settings.keys.test.unwrap_or(key));
            }
            if let Some(key) = keys.clean {
                settings.keys.clean = Some(settings.keys.clean.unwrap_or(key));
            }
            if let Some(key) = keys.stop {
                settings.keys.stop = Some(settings.keys.stop.unwrap_or(key))
            }

            if let Some(key) = keys.save {
                settings.keys.save = Some(settings.keys.save.unwrap_or(key));
            }
            if let Some(key) = keys.undo {
                settings.keys.undo = Some(settings.keys.undo.unwrap_or(key));
            }
            if let Some(key) = keys.redo {
                settings.keys.redo = Some(settings.keys.redo.unwrap_or(key));
            }
            if let Some(key) = keys.font_dec {
                settings.keys.font_dec = Some(settings.keys.font_dec.unwrap_or(key));
            }
            if let Some(key) = keys.font_inc {
                settings.keys.font_inc = Some(settings.keys.font_inc.unwrap_or(key));
            }
            if let Some(key) = keys.close {
                settings.keys.close = Some(settings.keys.close.unwrap_or(key));
            }

            return settings;
        }
    }

    default_settings
}
<|endoftext|>


<commit_before>use std::io::{Error, LineWriter, Write};
use vm::bytecode::{disassemble_instruction, BinaryOp, Chunk, OpCode, Value};

#[derive(Debug)]
pub enum RuntimeError {
    TracingError(Error),
    StackUnderflow,
    // The following out of bound errors have been found using
    // property based testing.
    // Unless I can statically determine that a chunk it is well-formed
    // they should be there, with a runtime penalty of bound checking
    // at every instruction
    InstructionOutOfBound,
    ValueOutOfBound,
}

struct Vm<'a> {
    chunk: &'a Chunk,
    program_counter: usize,
    stack: Vec<Value>,
}

impl<'a> Vm<'a> {
    fn new(chunk: &'a Chunk) -> Vm<'a> {
        Vm {
            chunk: chunk,
            program_counter: 0,
            stack: vec![],
        }
    }

    fn pop(&mut self) -> Result<Value, RuntimeError> {
        if let Some(value) = self.stack.pop() {
            Ok(value)
        } else {
            Err(RuntimeError::StackUnderflow)
        }
    }

    /// Interprets the next instruction.
    /// The execution of this function have some side effects including:
    ///  * update of the program counter to have it point to the next
    ///    instruction
    ///  * mutate the state of the stack
    ///
    /// This function true if there are other instructions left to execute
    /// or false if we're done interpreting the chunk.
    fn interpret_next(&mut self) -> Result<bool, RuntimeError> {
        self.program_counter += 1;
        if self.program_counter >= self.chunk.instruction_count() {
            return Err(RuntimeError::InstructionOutOfBound);
        }
        match self.chunk.get(self.program_counter - 1) {
            OpCode::Return => {
                let value = self.stack.pop();
                println!{"{:?}", value};
                // Temporarily changed the meaning
                return Ok(false);
            }
            OpCode::Constant(offset) => {
                if offset >= self.chunk.values_count() {
                    return Err(RuntimeError::ValueOutOfBound);
                }
                self.stack.push(self.chunk.get_value(offset))
            }
            OpCode::Negate => {
                let op = try!(self.pop());
                self.stack.push(-op);
            }
            OpCode::Binary(ref operator) => {
                // Note the order!
                // Op2 is the topmost element of the stack,
                // Op1 is the second topmost element
                let op2 = try!(self.pop());
                let op1 = try!(self.pop());
                self.stack.push(match operator {
                    &BinaryOp::Add => op1 + op2,
                    &BinaryOp::Subtract => op1 - op2,
                    &BinaryOp::Multiply => op1 * op2,
                    &BinaryOp::Divide => op1 / op2,
                })
            }
        };
        Ok(true)
    }
    fn trace<T>(&mut self, out: &mut LineWriter<T>) -> Result<(), Error>
    where
        T: Write,
    {
        try!(write!(out, "Stack: "));
        for value in self.stack.iter() {
            try!(write!(out, "[ {} ]", value));
        }
        try!(writeln!(out));
        if self.program_counter < self.chunk.instruction_count() {
            disassemble_instruction(&self.chunk.get(self.program_counter), self.chunk, out)
        } else {
            //TODO: is this really ok?
            Ok(())
        }
    }
}

pub fn interpret(chunk: &Chunk) -> Result<(), RuntimeError> {
    let mut vm = Vm::new(chunk);
    while try!{vm.interpret_next()} {}
    Ok(())
}

pub fn trace<T>(chunk: &Chunk, writer: &mut LineWriter<T>) -> Result<(), RuntimeError>
where
    T: Write,
{
    let mut vm = Vm::new(chunk);
    while {
        try!{vm.trace(writer).map_err(RuntimeError::TracingError)};
        try!{vm.interpret_next()}
    } {}
    Ok(())
}

#[cfg(test)]
mod tests {
    use proptest::collection::*;
    use proptest::num::*;
    use proptest::prelude::*;
    use proptest::strategy::*;
    use std::io::*;
    use vm::bytecode::*;
    use vm::*;

    fn arb_constants(max_constants: usize) -> VecStrategy<f64::Any> {
        prop::collection::vec(any::<Value>(), 0..max_constants)
    }

    fn arb_instruction(max_offset: usize) -> BoxedStrategy<OpCode> {
        prop_oneof![
            (0..max_offset).prop_map(OpCode::Constant),
            Just(OpCode::Return),
            Just(OpCode::Negate),
            prop_oneof![
                Just(BinaryOp::Add),
                Just(BinaryOp::Subtract),
                Just(BinaryOp::Multiply),
                Just(BinaryOp::Divide),
            ].prop_map(OpCode::Binary),
        ].boxed()
    }

    fn arb_instructions(
        max_offset: usize,
        max_instructions: usize,
    ) -> VecStrategy<BoxedStrategy<OpCode>> {
        prop::collection::vec(arb_instruction(max_offset), 0..max_instructions)
    }

    prop_compose!{
        fn arb_chunk(max_offset : usize, max_instructions : usize)
            (constants in arb_constants(max_offset),
             instructions in arb_instructions(max_offset, max_instructions)) -> Chunk{
            let mut chunk = Chunk::new();
            for constant in constants{
                let _offset = chunk.add_constant(constant);
            }
            let mut line = 0;
            for instruction in instructions{
                chunk.add_instruction(instruction, line);
                line = line + 1;
            }
            chunk
        }
    }

    proptest! {
    #[test]
    fn interpret_doesnt_crash(ref chunk in arb_chunk(10, 20)) {
        let _ = vm::interpret(chunk);
    }
    }

    proptest! {
    #[test]
    fn trace_doesnt_crash(ref chunk in arb_chunk(10, 20)) {
        let mut writer = LineWriter::new(sink());
        let _ = vm::trace(chunk, &mut writer);
    }
    }

    proptest! {
    #[test]
    fn disassemble_doesnt_crash(ref chunk in arb_chunk(10, 20)) {
        let mut writer = LineWriter::new(sink());
        let _ = disassemble(chunk, "Test", &mut writer);
    }
    }
}
<commit_msg>Unused imports<commit_after>use std::io::{Error, LineWriter, Write};
use vm::bytecode::{disassemble_instruction, BinaryOp, Chunk, OpCode, Value};

#[derive(Debug)]
pub enum RuntimeError {
    TracingError(Error),
    StackUnderflow,
    // The following out of bound errors have been found using
    // property based testing.
    // Unless I can statically determine that a chunk it is well-formed
    // they should be there, with a runtime penalty of bound checking
    // at every instruction
    InstructionOutOfBound,
    ValueOutOfBound,
}

struct Vm<'a> {
    chunk: &'a Chunk,
    program_counter: usize,
    stack: Vec<Value>,
}

impl<'a> Vm<'a> {
    fn new(chunk: &'a Chunk) -> Vm<'a> {
        Vm {
            chunk: chunk,
            program_counter: 0,
            stack: vec![],
        }
    }

    fn pop(&mut self) -> Result<Value, RuntimeError> {
        if let Some(value) = self.stack.pop() {
            Ok(value)
        } else {
            Err(RuntimeError::StackUnderflow)
        }
    }

    /// Interprets the next instruction.
    /// The execution of this function have some side effects including:
    ///  * update of the program counter to have it point to the next
    ///    instruction
    ///  * mutate the state of the stack
    ///
    /// This function true if there are other instructions left to execute
    /// or false if we're done interpreting the chunk.
    fn interpret_next(&mut self) -> Result<bool, RuntimeError> {
        self.program_counter += 1;
        if self.program_counter >= self.chunk.instruction_count() {
            return Err(RuntimeError::InstructionOutOfBound);
        }
        match self.chunk.get(self.program_counter - 1) {
            OpCode::Return => {
                let value = self.stack.pop();
                println!{"{:?}", value};
                // Temporarily changed the meaning
                return Ok(false);
            }
            OpCode::Constant(offset) => {
                if offset >= self.chunk.values_count() {
                    return Err(RuntimeError::ValueOutOfBound);
                }
                self.stack.push(self.chunk.get_value(offset))
            }
            OpCode::Negate => {
                let op = try!(self.pop());
                self.stack.push(-op);
            }
            OpCode::Binary(ref operator) => {
                // Note the order!
                // Op2 is the topmost element of the stack,
                // Op1 is the second topmost element
                let op2 = try!(self.pop());
                let op1 = try!(self.pop());
                self.stack.push(match operator {
                    &BinaryOp::Add => op1 + op2,
                    &BinaryOp::Subtract => op1 - op2,
                    &BinaryOp::Multiply => op1 * op2,
                    &BinaryOp::Divide => op1 / op2,
                })
            }
        };
        Ok(true)
    }
    fn trace<T>(&mut self, out: &mut LineWriter<T>) -> Result<(), Error>
    where
        T: Write,
    {
        try!(write!(out, "Stack: "));
        for value in self.stack.iter() {
            try!(write!(out, "[ {} ]", value));
        }
        try!(writeln!(out));
        if self.program_counter < self.chunk.instruction_count() {
            disassemble_instruction(&self.chunk.get(self.program_counter), self.chunk, out)
        } else {
            //TODO: is this really ok?
            Ok(())
        }
    }
}

pub fn interpret(chunk: &Chunk) -> Result<(), RuntimeError> {
    let mut vm = Vm::new(chunk);
    while try!{vm.interpret_next()} {}
    Ok(())
}

pub fn trace<T>(chunk: &Chunk, writer: &mut LineWriter<T>) -> Result<(), RuntimeError>
where
    T: Write,
{
    let mut vm = Vm::new(chunk);
    while {
        try!{vm.trace(writer).map_err(RuntimeError::TracingError)};
        try!{vm.interpret_next()}
    } {}
    Ok(())
}

#[cfg(test)]
mod tests {
    use proptest::collection::*;
    use proptest::num::*;
    use proptest::prelude::*;
    use std::io::*;
    use vm::bytecode::*;
    use vm::*;

    fn arb_constants(max_constants: usize) -> VecStrategy<f64::Any> {
        prop::collection::vec(any::<Value>(), 0..max_constants)
    }

    fn arb_instruction(max_offset: usize) -> BoxedStrategy<OpCode> {
        prop_oneof![
            (0..max_offset).prop_map(OpCode::Constant),
            Just(OpCode::Return),
            Just(OpCode::Negate),
            prop_oneof![
                Just(BinaryOp::Add),
                Just(BinaryOp::Subtract),
                Just(BinaryOp::Multiply),
                Just(BinaryOp::Divide),
            ].prop_map(OpCode::Binary),
        ].boxed()
    }

    fn arb_instructions(
        max_offset: usize,
        max_instructions: usize,
    ) -> VecStrategy<BoxedStrategy<OpCode>> {
        prop::collection::vec(arb_instruction(max_offset), 0..max_instructions)
    }

    prop_compose!{
        fn arb_chunk(max_offset : usize, max_instructions : usize)
            (constants in arb_constants(max_offset),
             instructions in arb_instructions(max_offset, max_instructions)) -> Chunk{
            let mut chunk = Chunk::new();
            for constant in constants{
                let _offset = chunk.add_constant(constant);
            }
            let mut line = 0;
            for instruction in instructions{
                chunk.add_instruction(instruction, line);
                line = line + 1;
            }
            chunk
        }
    }

    proptest! {
    #[test]
    fn interpret_doesnt_crash(ref chunk in arb_chunk(10, 20)) {
        let _ = vm::interpret(chunk);
    }
    }

    proptest! {
    #[test]
    fn trace_doesnt_crash(ref chunk in arb_chunk(10, 20)) {
        let mut writer = LineWriter::new(sink());
        let _ = vm::trace(chunk, &mut writer);
    }
    }

    proptest! {
    #[test]
    fn disassemble_doesnt_crash(ref chunk in arb_chunk(10, 20)) {
        let mut writer = LineWriter::new(sink());
        let _ = disassemble(chunk, "Test", &mut writer);
    }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Intel Corporation. All Rights Reserved.
// Copyright 2021 Alibaba Cloud Computing. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0

//! Struct to maintain state information and manipulate vhost-user queues.

use std::fs::File;
use std::io;
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use virtio_queue::Queue;
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
use vmm_sys_util::eventfd::EventFd;

/// Struct to maintain raw state information for a vhost-user queue.
pub struct VringState {
    queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
    kick: Option<EventFd>,
    call: Option<EventFd>,
    err: Option<EventFd>,
    enabled: bool,
}

impl VringState {
    fn new(atomic_mem: GuestMemoryAtomic<GuestMemoryMmap>, max_queue_size: u16) -> Self {
        VringState {
            queue: Queue::new(atomic_mem, max_queue_size),
            kick: None,
            call: None,
            err: None,
            enabled: false,
        }
    }

    /// Get a mutable reference to the underlying `Queue` object.
    pub fn get_queue_mut(&mut self) -> &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>> {
        &mut self.queue
    }

    /// Get a immutable reference to the underlying kick event fd.
    pub fn get_kick(&self) -> &Option<EventFd> {
        &self.kick
    }
}

/// Struct to maintain state information and manipulate a vhost-user queue.
#[derive(Clone)]
pub struct Vring {
    state: Arc<RwLock<VringState>>,
}

impl Vring {
    /// Get a immutable guard to the underlying raw `VringState` object.
    pub fn get_ref(&self) -> RwLockReadGuard<VringState> {
        self.state.read().unwrap()
    }

    /// Get a mutable guard to the underlying raw `VringState` object.
    pub fn get_mut(&self) -> RwLockWriteGuard<VringState> {
        self.state.write().unwrap()
    }

    pub(crate) fn new(mem: GuestMemoryAtomic<GuestMemoryMmap>, max_queue_size: u16) -> Self {
        Vring {
            state: Arc::new(RwLock::new(VringState::new(mem, max_queue_size))),
        }
    }

    pub(crate) fn set_enabled(&self, enabled: bool) {
        self.get_mut().enabled = enabled;
    }

    pub(crate) fn set_queue_info(&self, desc_table: u64, avail_ring: u64, used_ring: u64) {
        let mut state = self.get_mut();

        state.queue.desc_table = GuestAddress(desc_table);
        state.queue.avail_ring = GuestAddress(avail_ring);
        state.queue.used_ring = GuestAddress(used_ring);
    }

    pub(crate) fn queue_next_avail(&self) -> u16 {
        self.get_ref().queue.next_avail()
    }

    pub(crate) fn set_queue_next_avail(&self, base: u16) {
        self.get_mut().queue.set_next_avail(base);
    }

    pub(crate) fn set_queue_size(&self, num: u16) {
        self.get_mut().queue.size = num;
    }

    pub(crate) fn set_queue_event_idx(&self, enabled: bool) {
        self.get_mut().queue.set_event_idx(enabled);
    }

    pub(crate) fn set_queue_ready(&self, ready: bool) {
        self.get_mut().queue.ready = ready;
    }

    pub(crate) fn set_kick(&self, file: Option<File>) {
        // SAFETY:
        // EventFd requires that it has sole ownership of its fd. So does File, so this is safe.
        // Ideally, we'd have a generic way to refer to a uniquely-owned fd, such as that proposed
        // by Rust RFC #3128.
        self.get_mut().kick = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
    }

    pub(crate) fn read_kick(&self) -> io::Result<bool> {
        let state = self.get_ref();

        if let Some(kick) = &state.kick {
            kick.read()?;
        }

        Ok(state.enabled)
    }

    pub(crate) fn set_call(&self, file: Option<File>) {
        // SAFETY: see comment in set_kick()
        self.get_mut().call = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
    }

    pub(crate) fn set_err(&self, file: Option<File>) {
        // SAFETY: see comment in set_kick()
        self.get_mut().err = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
    }
}
<commit_msg>vring: introduce generic parameter type `M`<commit_after>// Copyright 2019 Intel Corporation. All Rights Reserved.
// Copyright 2021 Alibaba Cloud Computing. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0

//! Struct to maintain state information and manipulate vhost-user queues.

use std::fs::File;
use std::io;
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::result::Result;
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};

use virtio_queue::{Error as VirtQueError, Queue};
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
use vmm_sys_util::eventfd::EventFd;

/// Struct to maintain raw state information for a vhost-user queue.
pub struct VringState<M: GuestAddressSpace> {
    queue: Queue<M>,
    kick: Option<EventFd>,
    call: Option<EventFd>,
    err: Option<EventFd>,
    enabled: bool,
}

impl<M: GuestAddressSpace> VringState<M> {
    fn new(mem: M, max_queue_size: u16) -> Self {
        VringState {
            queue: Queue::new(mem, max_queue_size),
            kick: None,
            call: None,
            err: None,
            enabled: false,
        }
    }

    /// Get a mutable reference to the underlying raw `Queue` object.
    pub fn get_queue_mut(&mut self) -> &mut Queue<M> {
        &mut self.queue
    }

    /// Get a immutable reference to the kick event fd.
    pub fn get_kick(&self) -> &Option<EventFd> {
        &self.kick
    }
}

/// Struct to maintain state information and manipulate a vhost-user queue.
#[derive(Clone)]
pub struct Vring<M: GuestAddressSpace = GuestMemoryAtomic<GuestMemoryMmap>> {
    state: Arc<RwLock<VringState<M>>>,
}

impl<M: GuestAddressSpace> Vring<M> {
    /// Get a immutable guard to the underlying raw `VringState` object.
    pub fn get_ref(&self) -> RwLockReadGuard<VringState<M>> {
        self.state.read().unwrap()
    }

    /// Get a mutable guard to the underlying raw `VringState` object.
    pub fn get_mut(&self) -> RwLockWriteGuard<VringState<M>> {
        self.state.write().unwrap()
    }

    /// Add an used descriptor into the used queue.
    pub fn add_used(&self, desc_index: u16, len: u32) -> Result<(), VirtQueError> {
        self.get_mut().get_queue_mut().add_used(desc_index, len)
    }

    /// Notify the vhost-user master that used descriptors have been put into the used queue.
    pub fn signal_used_queue(&self) -> io::Result<()> {
        if let Some(call) = self.get_ref().call.as_ref() {
            call.write(1)
        } else {
            Ok(())
        }
    }

    /// Enable event notification for queue.
    pub fn enable_notification(&self) -> Result<bool, VirtQueError> {
        self.get_mut().get_queue_mut().enable_notification()
    }

    /// Disable event notification for queue.
    pub fn disable_notification(&self) -> Result<(), VirtQueError> {
        self.get_mut().get_queue_mut().disable_notification()
    }

    /// Check whether a notification to the guest is needed.
    pub fn needs_notification(&self) -> Result<bool, VirtQueError> {
        self.get_mut().get_queue_mut().needs_notification()
    }

    pub(crate) fn new(mem: M, max_queue_size: u16) -> Self {
        Vring {
            state: Arc::new(RwLock::new(VringState::new(mem, max_queue_size))),
        }
    }

    pub(crate) fn set_enabled(&self, enabled: bool) {
        self.get_mut().enabled = enabled;
    }

    pub(crate) fn set_queue_info(&self, desc_table: u64, avail_ring: u64, used_ring: u64) {
        let mut state = self.get_mut();

        state.queue.desc_table = GuestAddress(desc_table);
        state.queue.avail_ring = GuestAddress(avail_ring);
        state.queue.used_ring = GuestAddress(used_ring);
    }

    pub(crate) fn queue_next_avail(&self) -> u16 {
        self.get_ref().queue.next_avail()
    }

    pub(crate) fn set_queue_next_avail(&self, base: u16) {
        self.get_mut().queue.set_next_avail(base);
    }

    pub(crate) fn set_queue_size(&self, num: u16) {
        self.get_mut().queue.size = num;
    }

    pub(crate) fn set_queue_event_idx(&self, enabled: bool) {
        self.get_mut().queue.set_event_idx(enabled);
    }

    pub(crate) fn set_queue_ready(&self, ready: bool) {
        self.get_mut().queue.ready = ready;
    }

    pub(crate) fn set_kick(&self, file: Option<File>) {
        // SAFETY:
        // EventFd requires that it has sole ownership of its fd. So does File, so this is safe.
        // Ideally, we'd have a generic way to refer to a uniquely-owned fd, such as that proposed
        // by Rust RFC #3128.
        self.get_mut().kick = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
    }

    pub(crate) fn read_kick(&self) -> io::Result<bool> {
        let state = self.get_ref();

        if let Some(kick) = &state.kick {
            kick.read()?;
        }

        Ok(state.enabled)
    }

    pub(crate) fn set_call(&self, file: Option<File>) {
        // SAFETY: see comment in set_kick()
        self.get_mut().call = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
    }

    pub(crate) fn set_err(&self, file: Option<File>) {
        // SAFETY: see comment in set_kick()
        self.get_mut().err = file.map(|f| unsafe { EventFd::from_raw_fd(f.into_raw_fd()) });
    }
}
<|endoftext|>


<commit_before>#![feature(path_ext)]
#[cfg(not(windows))]
extern crate pkg_config;
use std::fs::{self, PathExt};
use std::env;
use std::path::Path;
use std::process::Command;

#[cfg(windows)]
static FINAL_LIB:&'static str = "libjit.dll";

#[cfg(not(windows))]
static FINAL_LIB:&'static str = "libjit.a";

static MINGW:&'static str = "c:/mingw";

static INSTALL_AUTOTOOLS_MSG:&'static str = "Failed to generate configuration script. Did you forget to install autotools, bison, flex, and libtool?";

static USE_CARGO_MSG:&'static str = "Build script should be ran with Cargo";

#[cfg(windows)]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install MinGW and MSYS?";
#[cfg(not(windows))]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install gcc or clang?";

fn parse(cmd: &str) -> Command {
	let mut words = cmd.split(' ');
	let mut command = Command::new(words.next().unwrap());
	for arg in words {
		command.arg(arg);
	}
	command
}

fn main() {
	if cfg!(windows) && !Path::new(MINGW).exists() {
		panic!("{}", INSTALL_COMPILER_MSG);
	} else if pkg_config::find_library("jit").is_ok() {
		println!("Copy of LibJIT found on system - no need to build");
		return;
	}
	let out_dir = env::var("OUT_DIR").ok().expect(USE_CARGO_MSG);
	let out_dir = Path::new(&*out_dir);
	let submod_path = Path::new("libjit");
	let final_lib_dir = submod_path.join("jit/.libs");
	if !final_lib_dir.join(FINAL_LIB).exists() {
		run_wocare(&mut parse("git submodule init"));
		run(&mut parse("git submodule update"));
		if !submod_path.exists() {
			run(Command::new("git").args(&["clone", "git://git.savannah.gnu.org/libjit.git", submod_path.to_str().unwrap()]))
		}
		run_nice(parse("sh auto_gen.sh").current_dir(submod_path), INSTALL_AUTOTOOLS_MSG);
		run_nice(parse("sh configure --enable-static --disable-shared CC=clang CFLAGS=-fPIC").current_dir(submod_path), INSTALL_COMPILER_MSG);
		run(Command::new("make").arg("j8").current_dir(submod_path));
	}
	let from = final_lib_dir.join(FINAL_LIB);
	let to = out_dir.join(FINAL_LIB);
	if let Err(error) = fs::copy(&from, &to) {
		panic!("Failed to copy library from {:?} to {:?} due to {}", from, to, error)
	}
	println!("cargo:rustc-link-lib=jit");
	println!("cargo:rustc-link-search=native={:?}", out_dir);
}
fn run_nice(cmd: &mut Command, text: &str) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed - {}", cmd, text)
	}
}
fn run(cmd: &mut Command) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed", cmd)
	}
}
fn run_wocare(cmd: &mut Command) {
	cmd.status().unwrap();
}
<commit_msg>Fix build scrpit<commit_after>#![feature(path_ext)]
#[cfg(not(windows))]
extern crate pkg_config;
use std::fs::{self, PathExt};
use std::env;
use std::path::Path;
use std::process::Command;

#[cfg(windows)]
static FINAL_LIB:&'static str = "libjit.dll";

#[cfg(not(windows))]
static FINAL_LIB:&'static str = "libjit.a";

static MINGW:&'static str = "c:/mingw";

static INSTALL_AUTOTOOLS_MSG:&'static str = "Failed to generate configuration script. Did you forget to install autotools, bison, flex, and libtool?";

static USE_CARGO_MSG:&'static str = "Build script should be ran with Cargo";

#[cfg(windows)]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install MinGW and MSYS?";
#[cfg(not(windows))]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install gcc or clang?";

fn parse(cmd: &str) -> Command {
	let mut words = cmd.split(' ');
	let mut command = Command::new(words.next().unwrap());
	for arg in words {
		command.arg(arg);
	}
	command
}

fn main() {
	if cfg!(windows) && !Path::new(MINGW).exists() {
		panic!("{}", INSTALL_COMPILER_MSG);
	} else if pkg_config::find_library("jit").is_ok() {
		println!("Copy of LibJIT found on system - no need to build");
		return;
	}
	let out_dir = env::var("OUT_DIR").ok().expect(USE_CARGO_MSG);
	let num_jobs = env::var("NUM_JOBS").ok().expect(USE_CARGO_MSG);
	let out_dir = Path::new(&*out_dir);
	let submod_path = Path::new("libjit");
	let final_lib_dir = submod_path.join("jit/.libs");
	if !final_lib_dir.join(FINAL_LIB).exists() {
		run_wocare(&mut parse("git submodule init"));
		run(&mut parse("git submodule update"));
		if !submod_path.exists() {
			run(Command::new("git").args(&["clone", "git://git.savannah.gnu.org/libjit.git", submod_path.to_str().unwrap()]))
		}
		run_nice(parse("sh auto_gen.sh").current_dir(submod_path), INSTALL_AUTOTOOLS_MSG);
		run_nice(parse("sh configure --enable-static --disable-shared CC=clang CFLAGS=-fPIC").current_dir(submod_path), INSTALL_COMPILER_MSG);
		run(Command::new("make").arg(&format!("-j{}", num_jobs)).current_dir(submod_path));
	}
	let from = final_lib_dir.join(FINAL_LIB);
	let to = out_dir.join(FINAL_LIB);
	if let Err(error) = fs::copy(&from, &to) {
		panic!("Failed to copy library from {:?} to {:?} due to {}", from, to, error)
	}
	println!("cargo:rustc-link-lib=jit");
	println!("cargo:rustc-link-search=native={:?}", out_dir);
}
fn run_nice(cmd: &mut Command, text: &str) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed - {}", cmd, text)
	}
}
fn run(cmd: &mut Command) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed", cmd)
	}
}
fn run_wocare(cmd: &mut Command) {
	cmd.status().unwrap();
}
<|endoftext|>


<commit_before>/*
    This file is part of trig-rs, a library for doing typesafe trigonometry
    with a variety of angle formats (radians, degrees, grad, turns, and so on).
*/

use std::fmt;

/// Base floating point types
pub trait BaseFloat: Primitive + fmt::Show + fmt::Float + Float + FloatMath {}

impl BaseFloat for f32 {}
impl BaseFloat for f64 {}

/// Encompasses representations of angles in the Euclidean plane.
#[deriving(Clone, PartialEq, PartialOrd, Hash)]
pub enum Angle<S> {
    /// An angle in radians.
    Rad(S),
    /// An angle in degrees.
    Deg(S),
    /// An angle in [gradians](http://en.wikipedia.org/wiki/Grad_(angle)).
    Grad(S),
    /// An angle in [turns](http://en.wikipedia.org/wiki/Turn_(geometry)).
    Turn(S),
    /// An angle as it would appear on the face of a clock.
    Clock {
        /// The hours portion.
        hour: S,
        /// The minutes portion.
        minute: S,
        /// The seconds portion.
        second: S
    },
}

impl<S: BaseFloat> Angle<S> {
    /// Returns an angle in radians.
    pub fn radians(s: S) -> Angle<S> { Rad(s) }

    /// Returns an angle in degrees.
    pub fn degrees(s: S) -> Angle<S> { Deg(s) }

    /// Converts an angle to radians.
    pub fn to_radians(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::radians(val),
            &Deg(val) => Angle::radians(val.to_radians()),
            _ => fail!("Not yet implemented.")
        }
    }

    /// Converts an angle to degrees.
    pub fn to_degrees(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::degrees(val.to_degrees()),
            &Deg(val) => Angle::degrees(val),
            _ => fail!("Not yet implemented.")
        }
    }
}

/// Represents an object for which trigonometric methods are sensible and return
/// values of type `S`.
pub trait Trigonometry<S> {
    /// Compute the sine of the object.
    fn sin(&self) -> S;
    /// Compute the cosine of the object.
    fn cos(&self) -> S;
    /// Compute the tangent of the object.
    fn tan(&self) -> S;
    // /// Compute the cosecant of the object.
    // fn csc(&self) -> S;
    // /// Compute the secant of the object.
    // fn sec(&self) -> S;
    // /// Compute the cotangent of the object.
    // fn cot(&self) -> S;
}

macro_rules! angle_trigonometry (
    ($($method:ident),+ ) => (
        impl<S: BaseFloat> Trigonometry<S> for Angle<S> {
            $(fn $method(&self) -> S {
                match self {
                    &Rad(val) => val.$method(),
                    &Deg(val) => val.to_radians().$method(),
                    _ => fail!("Not yet implemented.")
                }
            }
            )+
        }
    )
)

angle_trigonometry!(sin, cos, tan)

macro_rules! angle_ops (
    ($Trait:ident, $method:ident) => (
        impl<S: BaseFloat> $Trait<Angle<S>, Angle<S>> for Angle<S> {
            #[inline]
            fn $method(&self, other: &Angle<S>) -> Angle<S> {
                match (self, other) {
                    (&Deg(s1), &Deg(s2)) => Angle::degrees(s1.$method(&s2)),
                    (&Deg(s1), &Rad(s2)) => Angle::degrees(s1.$method(&s2.to_degrees())),
                    (&Rad(s1), &Rad(s2)) => Angle::radians(s1.$method(&s2)),
                    (&Rad(s1), &Deg(s2)) => Angle::radians(s1.$method(&s2.to_radians())),
                    _ => fail!("Not yet implemented.")
                }
            }
        }
    )
)

angle_ops!(Add, add)
angle_ops!(Sub, sub)
angle_ops!(Mul, mul)
angle_ops!(Div, div)

impl<S: BaseFloat + fmt::Show> fmt::Show for Angle<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Deg(val) => write!(f, "{}°", val),
            &Rad(val) => write!(f, "{} rad", val),
            &Grad(val) => write!(f, "{} gon", val),
            &Turn(val) => write!(f, "{} turns", val),
            _ => fail!("Not yet implemented.")
        }
    }
}
<commit_msg>Laid out more of the API.<commit_after>/*
    This file is part of trig-rs, a library for doing typesafe trigonometry
    with a variety of angle formats (radians, degrees, grad, turns, and so on).
*/

use std::fmt;

/// Base floating point types
pub trait BaseFloat: Primitive + fmt::Show + fmt::Float + Float + FloatMath {}

impl BaseFloat for f32 {}
impl BaseFloat for f64 {}

/// Encompasses representations of angles in the Euclidean plane.
#[deriving(Clone, PartialEq, PartialOrd, Hash)]
pub enum Angle<S> {
    /// An angle in radians.
    Rad(S),
    /// An angle in degrees.
    Deg(S),
    /// An angle in [gradians](http://en.wikipedia.org/wiki/Grad_(angle)).
    Grad(S),
    /// An angle in [turns](http://en.wikipedia.org/wiki/Turn_(geometry)).
    Turn(S),
    /// An angle as it would appear on the face of a clock.
    Clock {
        /// The hours portion.
        hour: S,
        /// The minutes portion.
        minute: S,
        /// The seconds portion.
        second: S
    },
}

impl<S: BaseFloat> Angle<S> {
    /// Returns an angle in radians.
    pub fn radians(s: S) -> Angle<S> { Rad(s) }

    /// Returns an angle in degrees.
    pub fn degrees(s: S) -> Angle<S> { Deg(s) }

    /// Returns an angle in gradians.
    pub fn gradians(s: S) -> Angle<S> { Grad(s) }

    /// Returns an angle in turns.
    pub fn turns(s: S) -> Angle<S> { Turn(s) }

    /// Returns an angle as it would appear on a clock.
    pub fn clock_face(hour: S, minute: S, second: S) -> Angle<S> {
        Clock { hour: hour, minute: minute, second: second }
    }

    /// Converts an angle to radians.
    pub fn to_radians(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::radians(val),
            &Deg(val) => Angle::radians(val.to_radians()),
            _ => fail!("Not yet implemented.")
        }
    }

    /// Converts an angle to degrees.
    pub fn to_degrees(&self) -> Angle<S> {
        match self {
            &Rad(val) => Angle::degrees(val.to_degrees()),
            &Deg(val) => Angle::degrees(val),
            _ => fail!("Not yet implemented.")
        }
    }

    /// One half of the domain. In radians, this is `π`.
    pub fn half() -> Angle<S> { Rad(Float::pi()) }

    /// One quarter of the domain. In radians, this is `π/2`.
    pub fn quarter() -> Angle<S> { Rad(Float::frac_pi_2()) }

    /// One sixth of the domain. In radians, this is `π/3`.
    pub fn sixth() -> Angle<S> { Rad(Float::frac_pi_3()) }

    /// One eighth of the domain. In radians, this is `π/4`.
    pub fn eighth() -> Angle<S> { Rad(Float::frac_pi_4()) }
}

/// Represents an object for which trigonometric methods are sensible and return
/// values of type `S`.
pub trait Trigonometry<S> {
    /// Compute the sine of the object.
    fn sin(&self) -> S;
    /// Compute the cosine of the object.
    fn cos(&self) -> S;
    /// Compute the tangent of the object.
    fn tan(&self) -> S;
    // /// Compute the cosecant of the object.
    // fn csc(&self) -> S;
    // /// Compute the secant of the object.
    // fn sec(&self) -> S;
    // /// Compute the cotangent of the object.
    // fn cot(&self) -> S;
}

macro_rules! angle_trigonometry (
    ($($method:ident),+ ) => (
        impl<S: BaseFloat> Trigonometry<S> for Angle<S> {
            $(fn $method(&self) -> S {
                match self {
                    &Rad(val) => val.$method(),
                    &Deg(val) => val.to_radians().$method(),
                    _ => fail!("Not yet implemented.")
                }
            }
            )+
        }
    )
)

angle_trigonometry!(sin, cos, tan)

macro_rules! angle_ops (
    ($Trait:ident, $method:ident) => (
        impl<S: BaseFloat> $Trait<Angle<S>, Angle<S>> for Angle<S> {
            #[inline]
            fn $method(&self, other: &Angle<S>) -> Angle<S> {
                match (self, other) {
                    (&Deg(s1), &Deg(s2)) => Angle::degrees(s1.$method(&s2)),
                    (&Deg(s1), &Rad(s2)) => Angle::degrees(s1.$method(&s2.to_degrees())),
                    (&Rad(s1), &Rad(s2)) => Angle::radians(s1.$method(&s2)),
                    (&Rad(s1), &Deg(s2)) => Angle::radians(s1.$method(&s2.to_radians())),
                    _ => fail!("Not yet implemented.")
                }
            }
        }
    )
)

angle_ops!(Add, add)
angle_ops!(Sub, sub)
angle_ops!(Mul, mul)
angle_ops!(Div, div)

impl<S: BaseFloat + fmt::Show> fmt::Show for Angle<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Deg(val) => write!(f, "{}°", val),
            &Rad(val) => write!(f, "{} rad", val),
            &Grad(val) => write!(f, "{} gon", val),
            &Turn(val) => write!(f, "{} turns", val),
            _ => fail!("Not yet implemented.")
        }
    }
}
<|endoftext|>


<commit_before>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }

    /// Create a new SoundData from the given file.
    pub fn from_file<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let file = &mut context.filesystem.open(path)?;
        SoundData::from_read(file)
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let data = {
            let file = &mut context.filesystem.open(path)?;
            SoundData::from_read(file)?
        };
        Source::from_data(context, data)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        self.sink.append(decoder);
        Ok(())
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Returns whether or not the source is stopped
    /// -- that is, has no more data to play.
    pub fn stopped(&self) -> bool {
        self.sink.empty()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing (ie, not paused
    /// and not stopped)
    pub fn playing(&self) -> bool {
        !self.paused() && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}
<commit_msg>Added ability to repeat an audio::Source<commit_after>//! Provides an interface to output sound to the user's speakers.
//!
//! It consists of two main types: `SoundData` is just raw sound data,
//! and a `Source` is a `SoundData` connected to a particular sound
//! channel.

use std::fmt;
use std::io;
use std::io::Read;
use std::path;

use std::sync::Arc;

use rodio;

use context::Context;
use GameError;
use GameResult;

/// A struct that contains all information for tracking sound info.
///
/// You generally don't have to create this yourself, it will be part
/// of your `Context` object.
pub struct AudioContext {
    endpoint: rodio::Endpoint,
}

impl AudioContext {
    /// Create new AudioContext.
    pub fn new() -> GameResult<AudioContext> {
        let error = GameError::AudioError(String::from(
            "Could not initialize sound system (for \
             some reason)",
        ));
        // This is deprecated in cpal but not in the most recent rodio (0.5.2) yet.
        #[allow(deprecated)]
        let e = rodio::get_default_endpoint().ok_or(error)?;
        Ok(AudioContext { endpoint: e })
    }
}

impl fmt::Debug for AudioContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<AudioContext: {:p}>", self)
    }
}

/// Static sound data stored in memory.
/// It is Arc'ed, so cheap to clone.
#[derive(Clone, Debug)]
pub struct SoundData(Arc<[u8]>);

impl SoundData {
    /// Copies the data in the given slice into a new SoundData object.
    pub fn from_bytes(data: &[u8]) -> Self {
        SoundData(Arc::from(data))
    }

    /// Creates a SoundData from any Read object; this involves
    /// copying it into a buffer.
    pub fn from_read<R>(reader: &mut R) -> GameResult<Self>
    where
        R: Read,
    {
        let mut buffer = Vec::new();
        reader.read_to_end(&mut buffer)?;

        Ok(SoundData::from(buffer))
    }

    /// Create a new SoundData from the given file.
    pub fn from_file<P: AsRef<path::Path>>(context: &mut Context, path: P) -> GameResult<Self> {
        let path = path.as_ref();
        let file = &mut context.filesystem.open(path)?;
        SoundData::from_read(file)
    }
}

impl From<Arc<[u8]>> for SoundData {
    #[inline]
    fn from(arc: Arc<[u8]>) -> Self {
        SoundData(arc)
    }
}

impl From<Vec<u8>> for SoundData {
    fn from(v: Vec<u8>) -> Self {
        SoundData(Arc::from(v))
    }
}

impl From<Box<[u8]>> for SoundData {
    fn from(b: Box<[u8]>) -> Self {
        SoundData(Arc::from(b))
    }
}

impl AsRef<[u8]> for SoundData {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

/// A source of audio data connected to a particular `Channel`.
/// Will stop playing when dropped.
// TODO: Check and see if this matches Love2d's semantics!
// Eventually it might read from a streaming decoder of some kind,
// but for now it is just an in-memory SoundData structure.
// The source of a rodio decoder must be Send, which something
// that contains a reference to a ZipFile is not, so we are going
// to just slurp all the data into memory for now.
// There's really a lot of work that needs to be done here, since
// rodio has gotten better (if still somewhat arcane) and our filesystem
// code has done the data-slurping-from-zip's for us
// but for now it works.
pub struct Source {
    data: io::Cursor<SoundData>,
    sink: rodio::Sink,
    repeat: bool,
}

impl Source {
    /// Create a new Source from the given file.
    pub fn new<P: AsRef<path::Path>>(context: &mut Context, path: P, repeat: bool) -> GameResult<Self> {
        let path = path.as_ref();
        let data = {
            let file = &mut context.filesystem.open(path)?;
            SoundData::from_read(file)?
        };
        Source::from_data(context, data, repeat)
    }

    /// Creates a new Source using the given SoundData object.
    pub fn from_data(context: &mut Context, data: SoundData, repeat: bool) -> GameResult<Self> {
        let sink = rodio::Sink::new(&context.audio_context.endpoint);
        let cursor = io::Cursor::new(data);
        Ok(Source {
            data: cursor,
            sink: sink,
            repeat,
        })
    }

    /// Plays the Source.
    pub fn play(&self) -> GameResult<()> {
        // Creating a new Decoder each time seems a little messy,
        // since it may do checking and data-type detection that is
        // redundant, but it's not super expensive.
        // See https://github.com/ggez/ggez/issues/98 for discussion
        use rodio::Source;
        let cursor = self.data.clone();
        let decoder = rodio::Decoder::new(cursor)?;
        if self.repeat {
            let repeating = decoder.repeat_infinite();
            self.sink.append(repeating);
        } else {
            self.sink.append(decoder);
        }
        Ok(())
    }

    /// Repeats playback infinitely on next play()
    pub fn to_repeat(&mut self, repeat: bool) {
        self.repeat = repeat;
    }

    /// Pauses playback
    pub fn pause(&self) {
        self.sink.pause()
    }

    /// Resumes playback
    pub fn resume(&self) {
        self.sink.play()
    }

    /// Stops playback
    pub fn stop(&self) {
        self.sink.stop()
    }

    /// Returns whether or not the source is stopped
    /// -- that is, has no more data to play.
    pub fn stopped(&self) -> bool {
        self.sink.empty()
    }

    /// Gets the current volume
    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    /// Sets the current volume
    pub fn set_volume(&mut self, value: f32) {
        self.sink.set_volume(value)
    }

    /// Get whether or not the source is paused
    pub fn paused(&self) -> bool {
        self.sink.is_paused()
    }

    /// Get whether or not the source is playing (ie, not paused
    /// and not stopped)
    pub fn playing(&self) -> bool {
        !self.paused() && !self.stopped()
    }
}

impl fmt::Debug for Source {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Audio source: {:p}>", self)
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
extern crate test;

use std::{fmt, rt};
use std::rand::{task_rng, Rng};
use std::sync::{Arc, TaskPool, RWLock, Semaphore};

#[cfg(test)]
use self::test::Bencher;

const LIVE_CELL: char = '@';
const DEAD_CELL: char = '.';

#[deriving(PartialEq, Eq, Clone)]
pub struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

pub struct WorkerPool {
  pool: TaskPool<()>,
  size: uint
}

impl WorkerPool {
  pub fn new(size: uint) -> WorkerPool {
    WorkerPool {
      pool: TaskPool::new(size, || proc(_) {}),
      size: size
    }
  }

  pub fn new_with_default_size() -> WorkerPool {
    WorkerPool::new(rt::default_sched_threads())
  }
}

struct FutureBoard {
  board: Vec<Vec<bool>>,
  tasks_done: uint,
}

impl FutureBoard {
  fn cells(&self) -> Vec<bool> {
    self.board.as_slice().concat_vec()
  }
}

struct BoardAdvancer {
  board: Board,
  next_board: RWLock<FutureBoard>,
  done: Semaphore
}

impl BoardAdvancer {
  fn new(board: &Board, num_tasks: uint) -> BoardAdvancer {
    BoardAdvancer {
      board: board.clone(),
      next_board: RWLock::new(FutureBoard {
        board: Vec::from_elem(num_tasks, vec![]),
        tasks_done: 0
      }),
      done: Semaphore::new(0)
    }
  }

  fn advance(board: &Board, workers: &mut WorkerPool) -> Vec<bool> {
    let shared_board = Arc::new(BoardAdvancer::new(board, workers.size));
    let length = board.len();
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks((length + workers.size - 1) / workers.size).collect();
    let task_count = tasks.clone().iter().len();

    for (i, task) in tasks.iter().enumerate() {
      let task_board = shared_board.clone();
      let task = task.to_vec();

      workers.pool.execute(proc(_) {
        let task_values = task.iter().map(|&idx|
          task_board.board.successor_cell(idx)
        ).collect::<Vec<bool>>();
        let mut task_results = task_board.next_board.write();
        *task_results.board.get_mut(i) = task_values;
        task_results.tasks_done += 1;
        if task_results.tasks_done == task_count { task_board.done.release(); }
      });

    };
    shared_board.done.acquire();
    shared_board.next_board.read().cells()
  }

}

impl Board {
  pub fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  pub fn random(&self) -> Board {
    let board = task_rng().gen_iter::<bool>().take(self.len()).collect();

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  pub fn parallel_next_generation(&self, workers: &mut WorkerPool) -> Board {
    let new_brd = BoardAdvancer::advance(self, workers);

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().filter(|&x| *x).count()
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows[0].len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd: Option<Vec<bool>> = rows.concat().into_bytes()
      .into_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      }).collect();

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      String::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
const TEST_BOARDS: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(TEST_BOARDS[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_string(), TEST_BOARDS[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  let ref mut workers = WorkerPool::new_with_default_size();

  assert_eq!(testing_board(1).parallel_next_generation(workers), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10u) { brd = brd.next_generation() }

  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  let ref mut workers = WorkerPool::new_with_default_size();

  b.iter(|| {
    for _ in range(0,10u) { brd = brd.parallel_next_generation(workers) }
  });
}
<commit_msg>avoid deprecated get_mut call<commit_after>#[cfg(test)]
extern crate test;

use std::{fmt, rt};
use std::rand::{task_rng, Rng};
use std::sync::{Arc, TaskPool, RWLock, Semaphore};

#[cfg(test)]
use self::test::Bencher;

const LIVE_CELL: char = '@';
const DEAD_CELL: char = '.';

#[deriving(PartialEq, Eq, Clone)]
pub struct Board {
  board: Vec<bool>,
  survive: Vec<uint>,
  born: Vec<uint>,
  rows: uint,
  cols: uint
}

pub struct WorkerPool {
  pool: TaskPool<()>,
  size: uint
}

impl WorkerPool {
  pub fn new(size: uint) -> WorkerPool {
    WorkerPool {
      pool: TaskPool::new(size, || proc(_) {}),
      size: size
    }
  }

  pub fn new_with_default_size() -> WorkerPool {
    WorkerPool::new(rt::default_sched_threads())
  }
}

struct FutureBoard {
  board: Vec<Vec<bool>>,
  tasks_done: uint,
}

impl FutureBoard {
  fn cells(&self) -> Vec<bool> {
    self.board.as_slice().concat_vec()
  }
}

struct BoardAdvancer {
  board: Board,
  next_board: RWLock<FutureBoard>,
  done: Semaphore
}

impl BoardAdvancer {
  fn new(board: &Board, num_tasks: uint) -> BoardAdvancer {
    BoardAdvancer {
      board: board.clone(),
      next_board: RWLock::new(FutureBoard {
        board: Vec::from_elem(num_tasks, vec![]),
        tasks_done: 0
      }),
      done: Semaphore::new(0)
    }
  }

  fn advance(board: &Board, workers: &mut WorkerPool) -> Vec<bool> {
    let shared_board = Arc::new(BoardAdvancer::new(board, workers.size));
    let length = board.len();
    let all_tasks: Vec<uint> = range(0, length).collect();
    let tasks: Vec<&[uint]> = all_tasks.as_slice().chunks((length + workers.size - 1) / workers.size).collect();
    let task_count = tasks.clone().iter().len();

    for (i, task) in tasks.iter().enumerate() {
      let task_board = shared_board.clone();
      let task = task.to_vec();

      workers.pool.execute(proc(_) {
        let task_values = task.iter().map(|&idx|
          task_board.board.successor_cell(idx)
        ).collect::<Vec<bool>>();
        let mut task_results = task_board.next_board.write();
        task_results.board[i] = task_values;
        task_results.tasks_done += 1;
        if task_results.tasks_done == task_count { task_board.done.release(); }
      });

    };
    shared_board.done.acquire();
    shared_board.next_board.read().cells()
  }

}

impl Board {
  pub fn new(rows: uint, cols: uint) -> Board {
    let born = vec![3];
    let survive = vec![2, 3];

    Board::new_with_custom_rules(rows, cols, born, survive)
  }

  fn new_with_custom_rules(rows: uint, cols: uint, born: Vec<uint>, survive: Vec<uint>) -> Board {
    let new_board = Vec::from_elem(rows * cols, false);

    Board { board  : new_board,
            born   : born,
            survive: survive,
            rows   : rows,
            cols   : cols }
  }

  fn len(&self) -> uint {
    self.rows * self.cols
  }

  fn next_board(&self, new_board: Vec<bool>) -> Board {
    assert!(new_board.len() == self.len());

    Board { board  : new_board,
            born   : self.born.clone(),
            survive: self.survive.clone(),
            rows   : self.rows,
            cols   : self.cols }
  }

  pub fn random(&self) -> Board {
    let board = task_rng().gen_iter::<bool>().take(self.len()).collect();

    self.next_board(board)
  }

  fn next_generation(&self) -> Board {
    let new_brd = Vec::from_fn(self.len(), |cell| self.successor_cell(cell));

    self.next_board(new_brd)
  }

  pub fn parallel_next_generation(&self, workers: &mut WorkerPool) -> Board {
    let new_brd = BoardAdvancer::advance(self, workers);

    self.next_board(new_brd)
  }

  fn cell_live(&self, x: uint, y: uint) -> bool {
    !(x >= self.cols || y >= self.rows) && self.board[y * self.cols + x]
  }

  fn living_neighbors(&self, x: uint, y: uint) -> uint {
    let neighbors = [
      self.cell_live(x-1, y-1), self.cell_live(x, y-1), self.cell_live(x+1, y-1),
      self.cell_live(x-1, y+0),                         self.cell_live(x+1, y+0),
      self.cell_live(x-1, y+1), self.cell_live(x, y+1), self.cell_live(x+1, y+1),
    ];
    neighbors.iter().filter(|&x| *x).count()
  }

  fn successor_cell(&self, cell:uint) -> bool {
    self.successor(cell % self.cols, cell / self.cols)
  }

  fn successor(&self, x:uint, y:uint) -> bool {
    let neighbors = self.living_neighbors(x, y);
    if self.cell_live(x, y) {
      self.survive.contains(&neighbors)
    } else {
      self.born.contains(&neighbors)
    }
  }

  fn from_str(string: &str) -> Option<Board> {
    let rows: Vec<&str> = string.split_terminator('\n').collect();
    let (row_cnt, col_cnt) = (rows[0].len(), rows.len());

    if rows.iter().any(|x| x.len() != row_cnt) { return None; };

    let brd: Option<Vec<bool>> = rows.concat().into_bytes()
      .into_iter().map(|c| match c as char {
        LIVE_CELL => Some(true),
        DEAD_CELL => Some(false),
        _         => None
      }).collect();

    match brd {
      Some(board) => Some(Board::new(row_cnt, col_cnt).next_board(board)),
      None        => None
    }
  }
}

impl fmt::Show for Board {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

    fn row_to_str(row: &[bool]) -> String {
      let chars: Vec<char> = row.iter().map(|&cell|
        if cell {LIVE_CELL} else {DEAD_CELL}
      ).collect();
      String::from_chars(chars.as_slice())
    }

    let rows: Vec<String> = self.board.as_slice().chunks(self.cols).map(|row|
      row_to_str(row)
    ).collect();

    write!(f, "{}", rows.connect("\n"))
  }
}

#[cfg(test)]
const TEST_BOARDS: [&'static str, ..3] = [
  ".@.\n.@@\n.@@",
  "...\n@@@\n...",
  ".@.\n.@.\n.@."
];

#[cfg(test)]
fn testing_board(n: uint) -> Board {
  Board::from_str(TEST_BOARDS[n]).unwrap()
}

#[test]
fn test_board_str_conversion() {
  assert_eq!(testing_board(0).to_string(), TEST_BOARDS[0].to_string());
}

#[test]
fn test_cell_live() {
  let brd = testing_board(0);
  assert!(!brd.cell_live(0, 0));
  assert!(brd.cell_live(2, 2));
}

#[test]
fn test_live_count() {
  let brd = testing_board(0);
  assert_eq!(brd.living_neighbors(0, 0), 2);
  assert_eq!(brd.living_neighbors(2, 2), 3);
}

#[test]
fn test_next_generation() {
  assert_eq!(testing_board(1).next_generation(), testing_board(2));
}

#[test]
fn test_parallel_next_generation() {
  let ref mut workers = WorkerPool::new_with_default_size();

  assert_eq!(testing_board(1).parallel_next_generation(workers), testing_board(2));
}

#[bench]
fn bench_random(b: &mut Bencher) {
  let brd = Board::new(200,200);
  b.iter(|| brd.random());
}

#[bench]
fn bench_ten_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  b.iter(||
    for _ in range(0,10u) { brd = brd.next_generation() }

  );
}

#[bench]
fn bench_ten_parallel_generations(b: &mut Bencher) {
  let mut brd = Board::new(200,200).random();
  let ref mut workers = WorkerPool::new_with_default_size();

  b.iter(|| {
    for _ in range(0,10u) { brd = brd.parallel_next_generation(workers) }
  });
}
<|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],
        }
    }

    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()
    }

    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::*;

    #[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>start getting sequences to clear<commit_after>use color::Color;
use game::Piece;

use std::ops::Range;

#[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_sequences_in_coordinate_list(
        &self,
        row_range: Range<usize>,
        col_range: Range<usize>,
    ) -> Vec<Vec<Piece>>
        {
        println!("callin it!");

        let sequence_clear_len = 4;

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

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

        for row in row_range {
            for col in col_range.clone() {
                let color = self.get(row, col);

                let prev_color = match sequence.last() {
                    Some(piece) => Some(piece.color()),
                    _ => None,
                };

                match (color, prev_color) {
                    (Some(ref c1), Some(ref c2)) if c1 == c2 => {
                        sequence.push(Piece {row: row, col: col, color: c1.clone() });
                    },
                    (Some(c1), None) => {
                        if sequence.len() >= sequence_clear_len {
                            sequences.push(sequence.clone());
                        }

                        sequence.clear();
                        sequence.push(Piece {row: row, col: col, color: c1.clone() });
                    },
                    _ => {
                        if sequence.len() >= sequence_clear_len {
                            sequences.push(sequence.clone());
                        }

                        sequence.clear();
                    }
                }
            }
        }

        if sequence.len() >= sequence_clear_len {
            sequences.push(sequence);
        }

        sequences
    }

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

        // vertical
        for col in 0..self.width() {
            let new_sequences = self.get_sequences_in_coordinate_list(
                (0..self.height()),
                (col..col+ 1),
            );

            for s in new_sequences {
                sequences.push(s);
            }
        }

        sequences
    }

    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_sequences_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_sequences_to_clear = vec![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 sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }
    */

    #[test]
    fn get_sequences_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_sequences_to_clear = vec![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 sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_to_clear);
    }

    #[test]
    fn get_sequences_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_sequences_to_clear: Vec<Vec<Piece>> = vec![];

        let sequences_to_clear = board.get_sequences_to_clear();

        assert_eq!(expected_sequences_to_clear, sequences_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|>