<commit_before>use clap;
use info::discovery_service_info;
use rayon::prelude::*;
use select::{select_collection, select_configuration, writable_environment};
use serde_json::{Value, to_string_pretty};
use wdsapi::collection;
use wdsapi::common::{ApiError, Credentials};
use wdsapi::configuration;
use wdsapi::document;
use wdsapi::environment;

pub fn delete_environment(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_id = writable_environment(&info).environment_id;

    match environment::delete(&info.creds, &env_id) {
        Ok(response) => {
            println!(
                "{}",
                to_string_pretty(&response).expect(
                    "Internal error: failed to format \
                                  delete_environment response",
                )
            )
        }
        Err(e) => println!("Failed to delete environment {}", e),
    }
}

pub fn delete_one_collection(
    creds: &Credentials,
    env_id: &str,
    collection_id: &str,
) {
    match collection::delete(creds, env_id, collection_id) {
        Ok(response) => {
            println!(
                "{}",
                to_string_pretty(&response).expect(
                    "Internal error: failed to format \
                                  delete_collection response",
                )
            )
        }
        Err(e) => println!("Failed to delete collection {}", e),
    }
}

pub fn delete_collection(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let env_id = writable_environment(&info).environment_id;
    if matches.is_present("all") {
        for collection in env_info.collections {
            delete_one_collection(
                &info.creds,
                &env_id,
                collection["collection_id"].as_str().unwrap(),
            )
        }
    } else {
        let collection = select_collection(&env_info, matches);
        delete_one_collection(
            &info.creds,
            &env_id,
            collection["collection_id"].as_str().unwrap(),
        )
    }
}

pub fn delete_one_configuration(
    creds: &Credentials,
    env_id: &str,
    configuration_id: &str,
) {
    match configuration::delete(creds, env_id, configuration_id) {
        Ok(response) => {
            println!(
                "{}",
                to_string_pretty(&response).expect(
                    "Internal error: failed to format \
                                  delete_configuration response",
                )
            )
        }
        Err(e) => println!("Failed to delete configuration {}", e),
    }
}

pub fn delete_configuration(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let env_id = writable_environment(&info).environment_id;
    if matches.is_present("all") {
        for configuration in env_info.configurations {
            let configuration_id =
                configuration["configuration_id"].as_str().expect(
                    "Internal error: missing configuration_id",
                );
            delete_one_configuration(&info.creds, &env_id, configuration_id)
        }
    } else {
        let configuration = select_configuration(&env_info, matches);
        let configuration_id =
            configuration["configuration_id"].as_str().expect(
                "Internal error: missing configuration_id",
            );
        delete_one_configuration(&info.creds, &env_id, configuration_id)
    }
}

pub fn delete_document(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let collection = select_collection(&env_info, matches);
    let env_id = env_info.environment_id;
    let col_id = collection["collection_id"].as_str().unwrap_or("");

    // I didn't figure out how to use the matches directly...
    let document_ids: Vec<&str> =
        matches.values_of("document_id")
               .expect(
            "Internal error: missing \
                                                  document_id",
        )
               .collect();

    let document_statuses: Vec<Result<Value, ApiError>> =
        document_ids.par_iter()
                    .map(|doc_id| {
            document::delete(&info.creds, &env_id, col_id, doc_id)
        })
                    .collect();

    for doc in document_statuses {
        match doc {
            Ok(response) => {
                println!(
                    "{}",
                    to_string_pretty(&response).expect(
                        "Internal error: failed to format \
                                      document::delete response",
                    )
                )
            }
            Err(e) => println!("Failed to lookup document {}", e),
        }
    }
}
<commit_msg>Minor code format cleanup<commit_after>use clap;
use info::discovery_service_info;
use rayon::prelude::*;
use select::{select_collection, select_configuration, writable_environment};
use serde_json::{Value, to_string_pretty};
use wdsapi::collection;
use wdsapi::common::{ApiError, Credentials};
use wdsapi::configuration;
use wdsapi::document;
use wdsapi::environment;

pub fn delete_environment(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_id = writable_environment(&info).environment_id;

    match environment::delete(&info.creds, &env_id) {
        Ok(response) => {
            println!(
                "{}",
                to_string_pretty(&response).expect(
                    "Internal error: failed to format \
                                  delete_environment response",
                )
            )
        }
        Err(e) => println!("Failed to delete environment {}", e),
    }
}

pub fn delete_one_collection(
    creds: &Credentials,
    env_id: &str,
    collection_id: &str,
) {
    match collection::delete(creds, env_id, collection_id) {
        Ok(response) => {
            println!(
                "{}",
                to_string_pretty(&response).expect(
                    "Internal error: failed to format \
                                  delete_collection response",
                )
            )
        }
        Err(e) => println!("Failed to delete collection {}", e),
    }
}

pub fn delete_collection(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let env_id = writable_environment(&info).environment_id;
    if matches.is_present("all") {
        for collection in env_info.collections {
            delete_one_collection(
                &info.creds,
                &env_id,
                collection["collection_id"].as_str().unwrap(),
            )
        }
    } else {
        let collection = select_collection(&env_info, matches);
        delete_one_collection(
            &info.creds,
            &env_id,
            collection["collection_id"].as_str().unwrap(),
        )
    }
}

pub fn delete_one_configuration(
    creds: &Credentials,
    env_id: &str,
    configuration_id: &str,
) {
    match configuration::delete(creds, env_id, configuration_id) {
        Ok(response) => {
            println!(
                "{}",
                to_string_pretty(&response).expect(
                    "Internal error: failed to format \
                                  delete_configuration response",
                )
            )
        }
        Err(e) => println!("Failed to delete configuration {}", e),
    }
}

pub fn delete_configuration(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let env_id = writable_environment(&info).environment_id;
    if matches.is_present("all") {
        for configuration in env_info.configurations {
            let configuration_id =
                configuration["configuration_id"].as_str().expect(
                    "Internal error: missing configuration_id",
                );
            delete_one_configuration(&info.creds, &env_id, configuration_id)
        }
    } else {
        let configuration = select_configuration(&env_info, matches);
        let configuration_id =
            configuration["configuration_id"].as_str().expect(
                "Internal error: missing configuration_id",
            );
        delete_one_configuration(&info.creds, &env_id, configuration_id)
    }
}

pub fn delete_document(creds: Credentials, matches: &clap::ArgMatches) {
    let info = discovery_service_info(creds);
    let env_info = writable_environment(&info);
    let collection = select_collection(&env_info, matches);
    let env_id = env_info.environment_id;
    let col_id = collection["collection_id"].as_str().unwrap_or("");

    // I didn't figure out how to use the matches directly...
    let document_ids: Vec<&str> =
        matches.values_of("document_id")
               .expect("Internal error: missing document_id")
               .collect();

    let document_statuses: Vec<Result<Value, ApiError>> =
        document_ids.par_iter()
                    .map(|doc_id| {
            document::delete(&info.creds, &env_id, col_id, doc_id)
        })
                    .collect();

    for doc in document_statuses {
        match doc {
            Ok(response) => {
                println!(
                    "{}",
                    to_string_pretty(&response).expect(
                        "Internal error: failed to format document::delete response")
                )
            }
            Err(e) => println!("Failed to lookup document {}", e),
        }
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
extern crate walkdir;

pub mod single_threaded;

use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::fs;
use self::crossbeam::sync::chase_lev;
use self::walkdir::WalkDir;
use regex::{RegexSet, Regex};
use std::path::PathBuf;
use colored::*;
use std::process::exit;
use utils::size;
use std::thread;
use error::*;
use types::FileSize;
use std::path::Path;

pub use walk_parallel::single_threaded::*;

/// Enum for messaging between workers/stealers
pub enum Status<T> {
    Done,
    Data(T),
}

/// The 'Walk' struct contains all the information we need to traverse a directory.
#[derive(Debug)]
pub struct Walk {
    pub path: PathBuf,
    gitignore: Option<RegexSet>,
    hgignore: Option<RegexSet>,
    darcs_boring: Option<RegexSet>,
    excludes: Option<Regex>,
    max_depth: Option<u8>,
    threshold: Option<u64>,
    start_depth: usize,
    nproc: usize,
    show_files: bool,
    get_blocks: bool,
    follow_symlinks: bool,
    artifacts_only: bool,
}

impl Walk {
    /// function to make output from a 'Walk', using one thread. It also takes an 'Arc<AtomicU64>'
    /// and will add the relevant directory sizes to it.
    pub fn print_dir(w: Walk, total: Arc<AtomicU64>) -> () {

        let excludes = match w.excludes {
            Some(ref x) => Some(x),
            _ => None,
        };

        let v = if excludes.is_some() || w.artifacts_only {
            read_all(
                &w.path,
                (w.start_depth as u8),
                w.max_depth,
                excludes,
                &w.gitignore,
                w.artifacts_only,
            )
        } else {
            read_all_fast(&w.path, (w.start_depth as u8), w.max_depth)
        };

        let subdir_size = v.file_size.get();

        total.fetch_add(subdir_size, Ordering::Relaxed);

        let mut to_print = if let Some(m) = w.threshold {
            subdir_size > m
        } else {
            true
        };

        if let Some(0) = w.max_depth {
            to_print = false;
        }

        if to_print {
            // filter by depth
            let mut v_filtered = v.filtered(w.threshold, !w.show_files, w.max_depth);

            v_filtered.display_tree(w.path);
        }
    }

    /// set the maximum depth to display
    pub fn set_depth(&mut self, d: u8) -> () {
        self.max_depth = Some(d);
    }

    /// set the regex for excludes
    pub fn set_regex(&mut self, r: Regex) -> () {
        self.excludes = Some(r);
    }

    /// set the minumum file size
    pub fn set_threshold(&mut self, n: u64) -> () {
        self.threshold = Some(n);
    }

    /// include files when printing
    pub fn with_files(&mut self) -> () {
        self.show_files = true;
    }

    /// include files when printing
    pub fn blocks(&mut self) -> () {
        self.get_blocks = true;
    }

    /// include files when printing
    pub fn artifacts_only(&mut self) -> () {
        self.artifacts_only = true;
    }

    fn get_proc(&self) -> usize {
        self.nproc
    }

    /// Create a new 'Walk' from a 'PathBuf' and the number
    /// of processor cores to be used.
    pub fn new(p: PathBuf, n: usize) -> Walk {
        Walk {
            path: p,
            gitignore: None,
            hgignore: None,
            darcs_boring: None,
            excludes: None,
            max_depth: None,
            threshold: None,
            start_depth: 0,
            nproc: n,
            show_files: false,
            get_blocks: false,
            follow_symlinks: false,
            artifacts_only: false,
        }
    }

    fn bump_depth(&mut self) -> () {
        self.start_depth += 1;
    }

    /// This takes a 'Walk' and a 'Worker<Status<Walk>>' and executes the walk *in parallel*,
    /// creating new work for each subdirectory. It's not the most efficient concurrency
    /// imaginable, but it's fast and easy-ish to use. It *also* takes in an 'Arc<AtomicU64>',
    /// which it updates with any file sizes in the directory.
    pub fn push_subdir(
        w: &Walk,
        mut worker: &mut chase_lev::Worker<Status<Walk>>,
        total: Arc<AtomicU64>,
    ) {

        let in_paths = &w.path;

        // fill up queue + print out files
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let val = match p {
                    Ok(x) => x,
                    _ => {
                        eprintln!("{}: path error at {:?}.", "Error".red(), p);
                        exit(0x0001)
                    }
                };

                let exclude_check = if let Some(ref x) = w.excludes {
                    if let Some(r) = val.path().into_os_string().to_str() {
                        !x.is_match(r)
                    } else {
                        eprintln!(
                            "{}: ignoring invalid unicode at: {:?}",
                            "Warning".yellow(),
                            val.path().display()
                        );
                        true
                    }
                } else {
                    true
                };

                if exclude_check {
                    match val.file_type() {
                        Ok(t) => {
                            if t.is_dir() {
                                let mut new_path = w.path.to_owned();
                                new_path.push(val.file_name());
                                let mut new_walk = Walk::new(new_path, w.get_proc());
                                if w.excludes.is_some() {
                                    new_walk.set_regex(w.excludes.clone().unwrap());
                                }
                                if w.show_files {
                                    new_walk.with_files();
                                }
                                new_walk.bump_depth();
                                if let Some(d) = w.max_depth {
                                    new_walk.set_depth(d);
                                }
                                if let Some(b) = w.threshold {
                                    new_walk.set_threshold(b);
                                }
                                worker.push(Status::Data(new_walk)); // pass a vector of Arc's to do 2-level traversals?
                            } else if t.is_file() {
                                if let Ok(l) = val.metadata() {
                                    let size = size(&l, w.get_blocks); // l.len();
                                    total.fetch_add(size, Ordering::Relaxed);
                                    if w.show_files && size != 0 {
                                        let to_formatted = format!("{}", FileSize::new(size));
                                        println!(
                                            "{}\t {}",
                                            &to_formatted.green(),
                                            val.path().display()
                                        );
                                    }
                                } else {
                                    eprintln!(
                                        "{}: could not find filesize for file at {}.",
                                        "Warning".yellow(),
                                        val.path().display()
                                    );
                                }
                            }
                        }
                        _ => {
                            eprintln!(
                                "{}: could not determine file type for: {}",
                                "Warning".yellow(),
                                val.path().display()
                            )
                        }
                    }
                }
            }

            // send "done" messages to all the workers
            let iter = 0..(w.get_proc());
            iter.map(|_| worker.push(Status::Done)).count();

        }
        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!(
                "{}: path '{}' does not exist, or you do not have permission to enter.",
                "Error".red(),
                &in_paths.display()
            );
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            if w.artifacts_only {
                eprintln!(
                    "{}: {} is not a directory; not searching for artifacts",
                    "Warning".yellow(),
                    &in_paths.display()
                );
            }

            if let Ok(l) = in_paths.metadata() {
                let size = size(&l, w.get_blocks); // l.len();
                let to_formatted = format!("{}", FileSize::new(size));
                println!("{}\t {}", &to_formatted.green(), in_paths.display());
            } else {
                panic!("{}", Internal::IoError);
            }
        }
        // 3: otherwise, give a warning about permissions
        else {
            eprintln!(
                "{}: permission denied for directory: {}",
                "Warning".yellow(),
                &in_paths.display()
            );
        }

    }
}

fn latex_log<P: AsRef<Path>>(p: P) -> bool {

    lazy_static! {
        static ref LOG: Regex =
            Regex::new(r"\.log$")
            .unwrap();
    }

    if LOG.is_match(&p.as_ref().to_string_lossy().to_string()) {
        let mut parent = (&p.as_ref()).parent().unwrap().to_string_lossy().to_string();
        parent.push_str("/*.tex");
        glob_exists(&parent)
    }
    else {
        false
    }

}

// TODO figure out why the unwrap_or is failing?
// FIXME take optional reference to a regex
pub fn clean_project_dirs<P: AsRef<Path>>(p: P, exclude: Option<Regex>) -> () {

    lazy_static! {
        static ref REGEX: Regex =
            Regex::new(r"\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|hc|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|go\.(v|teak)|p_hi|p_o|prof|tix|synctex\.gz)$")
            .unwrap();
    }

    for dir in WalkDir::new(p)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|p| exclude.clone().map(|e| e.is_match(&p.path().to_string_lossy().to_string())) != Some(false))
        .filter(|p| REGEX.is_match(&p.path().to_string_lossy().to_string())
                || is_project_dir(&p.path().to_string_lossy().to_string(), &p.path().file_name().map(|x| x.to_string_lossy().to_string()).unwrap_or("".to_string()))
                || latex_log(&p.path()))
    {
        if dir.file_type().is_file() {
            fs::remove_file(dir.path()).unwrap_or(());
        }
        else if dir.file_type().is_dir() {
            fs::remove_dir_all(dir.path()).unwrap_or(());
        }
    }
}

/// Given a 'Walk' struct, traverse it concurrently and print out any relevant outputs.
/// Currently, this only works for a depth of two, which is probably bad.
pub fn print_parallel(w: Walk) -> () {

    // initialize the total at 0 and create a reference to it
    let val = AtomicU64::new(0);
    let arc = Arc::new(val);
    let arc_producer = arc.clone();
    let arc_child = arc.clone();
    let path_display = w.path.clone();

    // set up worker & stealer
    let (mut worker, stealer): (chase_lev::Worker<Status<Walk>>,
                                chase_lev::Stealer<Status<Walk>>) = chase_lev::deque();

    // set up our iterator for the workers
    let iter = 0..(&w.get_proc() - 1);

    // create the producer in another thread
    let child_producer = thread::spawn(move || {

        let arc_local = arc_producer.clone();

        // assign work to everyone
        Walk::push_subdir(&w, &mut worker, arc_local.clone());

        // start popping off values in the worker's thread
        loop {
            if let Some(p) = worker.try_pop() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        }

    });

    // create a vector of thread handles so that it doesn't execute
    // everything sequentially.
    let mut threads = Vec::new();

    // set up as many workers as we have threads
    for _ in iter {

        // create a new stealer
        let stealer_clone = stealer.clone();

        let arc_local = arc_child.clone();

        // run the stealer in a new thread
        let child_consumer = thread::spawn(move || loop {

            if let chase_lev::Steal::Data(p) = stealer_clone.steal() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        });

        threads.push(child_consumer);

    }

    // join the child producer to the main thread
    let _ = child_producer.join();

    // join the workers to the main thread
    let _ = threads
        .into_iter()
        .map(|v| {
            let result = v.join();
            if let Ok(exit) = result {
                exit
            } else if let Err(e) = result {
                panic!("{:?}", e)
            }
        })
        .count();

    // get the total size
    let m = arc.load(Ordering::SeqCst); // TODO - check if this works with Relaxed?
    let size = FileSize::new(m);

    // print directory total.
    if size != FileSize::new(0) {
        let to_formatted = format!("{}", size);
        println!("{}\t {}", &to_formatted.green(), path_display.display());
    }

}
<commit_msg>smol release<commit_after>extern crate crossbeam;
extern crate walkdir;

pub mod single_threaded;

use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::fs;
use self::crossbeam::sync::chase_lev;
use self::walkdir::WalkDir;
use regex::{RegexSet, Regex};
use std::path::PathBuf;
use colored::*;
use std::process::exit;
use utils::size;
use std::thread;
use error::*;
use types::FileSize;
use std::path::Path;

pub use walk_parallel::single_threaded::*;

/// Enum for messaging between workers/stealers
pub enum Status<T> {
    Done,
    Data(T),
}

/// The 'Walk' struct contains all the information we need to traverse a directory.
#[derive(Debug)]
pub struct Walk {
    pub path: PathBuf,
    gitignore: Option<RegexSet>,
    hgignore: Option<RegexSet>,
    darcs_boring: Option<RegexSet>,
    excludes: Option<Regex>,
    max_depth: Option<u8>,
    threshold: Option<u64>,
    start_depth: usize,
    nproc: usize,
    show_files: bool,
    get_blocks: bool,
    follow_symlinks: bool,
    artifacts_only: bool,
}

impl Walk {
    /// function to make output from a 'Walk', using one thread. It also takes an 'Arc<AtomicU64>'
    /// and will add the relevant directory sizes to it.
    pub fn print_dir(w: Walk, total: Arc<AtomicU64>) -> () {

        let excludes = match w.excludes {
            Some(ref x) => Some(x),
            _ => None,
        };

        let v = if excludes.is_some() || w.artifacts_only {
            read_all(
                &w.path,
                (w.start_depth as u8),
                w.max_depth,
                excludes,
                &w.gitignore,
                w.artifacts_only,
            )
        } else {
            read_all_fast(&w.path, (w.start_depth as u8), w.max_depth)
        };

        let subdir_size = v.file_size.get();

        total.fetch_add(subdir_size, Ordering::Relaxed);

        let mut to_print = if let Some(m) = w.threshold {
            subdir_size > m
        } else {
            true
        };

        if let Some(0) = w.max_depth {
            to_print = false;
        }

        if to_print {
            // filter by depth
            let mut v_filtered = v.filtered(w.threshold, !w.show_files, w.max_depth);

            v_filtered.display_tree(w.path);
        }
    }

    /// set the maximum depth to display
    pub fn set_depth(&mut self, d: u8) -> () {
        self.max_depth = Some(d);
    }

    /// set the regex for excludes
    pub fn set_regex(&mut self, r: Regex) -> () {
        self.excludes = Some(r);
    }

    /// set the minumum file size
    pub fn set_threshold(&mut self, n: u64) -> () {
        self.threshold = Some(n);
    }

    /// include files when printing
    pub fn with_files(&mut self) -> () {
        self.show_files = true;
    }

    /// include files when printing
    pub fn blocks(&mut self) -> () {
        self.get_blocks = true;
    }

    /// include files when printing
    pub fn artifacts_only(&mut self) -> () {
        self.artifacts_only = true;
    }

    fn get_proc(&self) -> usize {
        self.nproc
    }

    /// Create a new 'Walk' from a 'PathBuf' and the number
    /// of processor cores to be used.
    pub fn new(p: PathBuf, n: usize) -> Walk {
        Walk {
            path: p,
            gitignore: None,
            hgignore: None,
            darcs_boring: None,
            excludes: None,
            max_depth: None,
            threshold: None,
            start_depth: 0,
            nproc: n,
            show_files: false,
            get_blocks: false,
            follow_symlinks: false,
            artifacts_only: false,
        }
    }

    fn bump_depth(&mut self) -> () {
        self.start_depth += 1;
    }

    /// This takes a 'Walk' and a 'Worker<Status<Walk>>' and executes the walk *in parallel*,
    /// creating new work for each subdirectory. It's not the most efficient concurrency
    /// imaginable, but it's fast and easy-ish to use. It *also* takes in an 'Arc<AtomicU64>',
    /// which it updates with any file sizes in the directory.
    pub fn push_subdir(
        w: &Walk,
        mut worker: &mut chase_lev::Worker<Status<Walk>>,
        total: Arc<AtomicU64>,
    ) {

        let in_paths = &w.path;

        // fill up queue + print out files
        if let Ok(paths) = fs::read_dir(in_paths) {

            // iterate over all the entries in the directory
            for p in paths {
                let val = match p {
                    Ok(x) => x,
                    _ => {
                        eprintln!("{}: path error at {:?}.", "Error".red(), p);
                        exit(0x0001)
                    }
                };

                let exclude_check = if let Some(ref x) = w.excludes {
                    if let Some(r) = val.path().into_os_string().to_str() {
                        !x.is_match(r)
                    } else {
                        eprintln!(
                            "{}: ignoring invalid unicode at: {:?}",
                            "Warning".yellow(),
                            val.path().display()
                        );
                        true
                    }
                } else {
                    true
                };

                if exclude_check {
                    match val.file_type() {
                        Ok(t) => {
                            if t.is_dir() {
                                let mut new_path = w.path.to_owned();
                                new_path.push(val.file_name());
                                let mut new_walk = Walk::new(new_path, w.get_proc());
                                if w.excludes.is_some() {
                                    new_walk.set_regex(w.excludes.clone().unwrap());
                                }
                                if w.show_files {
                                    new_walk.with_files();
                                }
                                new_walk.bump_depth();
                                if let Some(d) = w.max_depth {
                                    new_walk.set_depth(d);
                                }
                                if let Some(b) = w.threshold {
                                    new_walk.set_threshold(b);
                                }
                                worker.push(Status::Data(new_walk)); // pass a vector of Arc's to do 2-level traversals?
                            } else if t.is_file() {
                                if let Ok(l) = val.metadata() {
                                    let size = size(&l, w.get_blocks); // l.len();
                                    total.fetch_add(size, Ordering::Relaxed);
                                    if w.show_files && size != 0 {
                                        let to_formatted = format!("{}", FileSize::new(size));
                                        println!(
                                            "{}\t {}",
                                            &to_formatted.green(),
                                            val.path().display()
                                        );
                                    }
                                } else {
                                    eprintln!(
                                        "{}: could not find filesize for file at {}.",
                                        "Warning".yellow(),
                                        val.path().display()
                                    );
                                }
                            }
                        }
                        _ => {
                            eprintln!(
                                "{}: could not determine file type for: {}",
                                "Warning".yellow(),
                                val.path().display()
                            )
                        }
                    }
                }
            }

            // send "done" messages to all the workers
            let iter = 0..(w.get_proc());
            iter.map(|_| worker.push(Status::Done)).count();

        }
        // if we can't read the directory contents, figure out why
        // 1: check the path exists
        else if !in_paths.exists() {
            eprintln!(
                "{}: path '{}' does not exist, or you do not have permission to enter.",
                "Error".red(),
                &in_paths.display()
            );
        }
        // 2: check the path is actually a directory
        else if !in_paths.is_dir() {
            if w.artifacts_only {
                eprintln!(
                    "{}: {} is not a directory; not searching for artifacts",
                    "Warning".yellow(),
                    &in_paths.display()
                );
            }

            if let Ok(l) = in_paths.metadata() {
                let size = size(&l, w.get_blocks); // l.len();
                let to_formatted = format!("{}", FileSize::new(size));
                println!("{}\t {}", &to_formatted.green(), in_paths.display());
            } else {
                panic!("{}", Internal::IoError);
            }
        }
        // 3: otherwise, give a warning about permissions
        else {
            eprintln!(
                "{}: permission denied for directory: {}",
                "Warning".yellow(),
                &in_paths.display()
            );
        }

    }
}

fn latex_log<P: AsRef<Path>>(p: P) -> bool {

    lazy_static! {
        static ref LOG: Regex =
            Regex::new(r"\.log$")
            .unwrap();
    }

    if LOG.is_match(&p.as_ref().to_string_lossy().to_string()) {
        let mut parent = (&p.as_ref()).parent().unwrap().to_string_lossy().to_string();
        parent.push_str("/*.tex");
        glob_exists(&parent)
    }
    else {
        false
    }

}

// TODO figure out why the unwrap_or is failing?
// FIXME take optional reference to a regex
pub fn clean_project_dirs<P: AsRef<Path>>(p: P, exclude: Option<Regex>) -> () {

    lazy_static! {
        static ref REGEX: Regex =
            Regex::new(r"\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|hc|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|go\.(v|teak|xmldef)|p_hi|p_o|prof|tix|synctex\.gz)$")
            .unwrap();
    }

    for dir in WalkDir::new(p)
        .into_iter()
        .filter_map(|e| e.ok())
        .filter(|p| exclude.clone().map(|e| e.is_match(&p.path().to_string_lossy().to_string())) != Some(false))
        .filter(|p| REGEX.is_match(&p.path().to_string_lossy().to_string())
                || is_project_dir(&p.path().to_string_lossy().to_string(), &p.path().file_name().map(|x| x.to_string_lossy().to_string()).unwrap_or("".to_string()))
                || latex_log(&p.path()))
    {
        if dir.file_type().is_file() {
            fs::remove_file(dir.path()).unwrap_or(());
        }
        else if dir.file_type().is_dir() {
            fs::remove_dir_all(dir.path()).unwrap_or(());
        }
    }
}

/// Given a 'Walk' struct, traverse it concurrently and print out any relevant outputs.
/// Currently, this only works for a depth of two, which is probably bad.
pub fn print_parallel(w: Walk) -> () {

    // initialize the total at 0 and create a reference to it
    let val = AtomicU64::new(0);
    let arc = Arc::new(val);
    let arc_producer = arc.clone();
    let arc_child = arc.clone();
    let path_display = w.path.clone();

    // set up worker & stealer
    let (mut worker, stealer): (chase_lev::Worker<Status<Walk>>,
                                chase_lev::Stealer<Status<Walk>>) = chase_lev::deque();

    // set up our iterator for the workers
    let iter = 0..(&w.get_proc() - 1);

    // create the producer in another thread
    let child_producer = thread::spawn(move || {

        let arc_local = arc_producer.clone();

        // assign work to everyone
        Walk::push_subdir(&w, &mut worker, arc_local.clone());

        // start popping off values in the worker's thread
        loop {
            if let Some(p) = worker.try_pop() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        }

    });

    // create a vector of thread handles so that it doesn't execute
    // everything sequentially.
    let mut threads = Vec::new();

    // set up as many workers as we have threads
    for _ in iter {

        // create a new stealer
        let stealer_clone = stealer.clone();

        let arc_local = arc_child.clone();

        // run the stealer in a new thread
        let child_consumer = thread::spawn(move || loop {

            if let chase_lev::Steal::Data(p) = stealer_clone.steal() {
                match p {
                    Status::Data(d) => Walk::print_dir(d, arc_local.clone()),
                    _ => break,
                };
            }
        });

        threads.push(child_consumer);

    }

    // join the child producer to the main thread
    let _ = child_producer.join();

    // join the workers to the main thread
    let _ = threads
        .into_iter()
        .map(|v| {
            let result = v.join();
            if let Ok(exit) = result {
                exit
            } else if let Err(e) = result {
                panic!("{:?}", e)
            }
        })
        .count();

    // get the total size
    let m = arc.load(Ordering::SeqCst); // TODO - check if this works with Relaxed?
    let size = FileSize::new(m);

    // print directory total.
    if size != FileSize::new(0) {
        let to_formatted = format!("{}", size);
        println!("{}\t {}", &to_formatted.green(), path_display.display());
    }

}
<|endoftext|>


<commit_before>//! Standard Rust log crate adapter to slog-rs
//!
//! Note: `slog-stdlog` for slog v2, unlike previous releases uses logging
//! scopes provided by `slog-scope` crate instead of providing it's own ones.
//!
//! This crate provides two way compatibility with legacy `log` crate logging.
//!
//! ### `log` -> `slog`
//!
//! After calling `init` legacy `log` crate logging statements (eg.
//! `debug!(...)`) will be redirected just like they originated from the logger
//! returned by `slog_scope::logger()`.  See documentation of `slog-scope` for
//! examples of logging scope usage.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is a `slog::Drain` implementation that will log logging `Record`s
//! just like they were created using legacy `log` statements.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily
//! created: `log` -> `slog` -> `log` -> ...
//!
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_scope;
extern crate log;

use log::LogMetadata;
use std::{io, fmt};

use slog::Level;
use slog::KV;

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();

        let s = slog::RecordStatic {
            location: &slog::RecordLocation {
                file: file,
                line: line,
                column: 0,
                function: "",
                module: module,
            },
            level: level,
            tag: target,
        };
        slog_scope::logger().log(&slog::Record::new(&s, args, b!()))
    }
}

/// Minimal initialization with default drain
///
/// The exact default drain is unspecified and will
/// change in future versions! Use `set_logger` instead
/// to build customized drain.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::max());
        Box::new(Logger)
    })
}

/// Drain logging `Record`s into `log` crate
///
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
/// other standard logging statements.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKVList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io);

        let res = {
                || -> io::Result<()> {
                    try!(self.logger_values.serialize(self.info, &mut ser));
                    try!(self.info.kv().serialize(self.info, &mut ser));
                    Ok(())
                }
            }()
            .map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Err = io::Error;
    type Ok = ();
    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.tag();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W) -> Self {
        KSV {
            io: io,
        }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> slog::Serializer for KSV<W> {
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> slog::Result {
        try!(write!(self.io, ", {}: {}", key, val));
        Ok(())
    }
}
<commit_msg>Document how to do compile-time log level filtering<commit_after>//! Standard Rust log crate adapter to slog-rs
//!
//! Note: `slog-stdlog` for slog v2, unlike previous releases uses logging
//! scopes provided by `slog-scope` crate instead of providing it's own ones.
//!
//! This crate provides two way compatibility with legacy `log` crate logging.
//!
//! ### `log` -> `slog`
//!
//! After calling `init` legacy `log` crate logging statements (eg.
//! `debug!(...)`) will be redirected just like they originated from the logger
//! returned by `slog_scope::logger()`.  See documentation of `slog-scope` for
//! examples of logging scope usage.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is a `slog::Drain` implementation that will log logging `Record`s
//! just like they were created using legacy `log` statements.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily
//! created: `log` -> `slog` -> `log` -> ...
//!
//! ## Compile-time log level filtering
//!
//! For filtering `debug!` and other `log` statements at compile-time, configure the features on
//! the `log` crate in your `Cargo.toml`:
//!
//! ```norust
//! log = { version = "*", features = ["max_level_trace", "release_max_level_warn"] }
//! ```
#![warn(missing_docs)]

#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_scope;
extern crate log;

use log::LogMetadata;
use std::{io, fmt};

use slog::Level;
use slog::KV;

struct Logger;

fn log_to_slog_level(level: log::LogLevel) -> Level {
    match level {
        log::LogLevel::Trace => Level::Trace,
        log::LogLevel::Debug => Level::Debug,
        log::LogLevel::Info => Level::Info,
        log::LogLevel::Warn => Level::Warning,
        log::LogLevel::Error => Level::Error,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, r: &log::LogRecord) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let module = r.location().__module_path;
        let file = r.location().__file;
        let line = r.location().line();

        let s = slog::RecordStatic {
            location: &slog::RecordLocation {
                file: file,
                line: line,
                column: 0,
                function: "",
                module: module,
            },
            level: level,
            tag: target,
        };
        slog_scope::logger().log(&slog::Record::new(&s, args, b!()))
    }
}

/// Minimal initialization with default drain
///
/// The exact default drain is unspecified and will
/// change in future versions! Use `set_logger` instead
/// to build customized drain.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// extern crate slog_stdlog;
///
/// fn main() {
///     slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(log::LogLevelFilter::max());
        Box::new(Logger)
    })
}

/// Drain logging `Record`s into `log` crate
///
/// Using `StdLog` is effectively the same as using `log::info!(...)` and
/// other standard logging statements.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKVList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {

        LazyLogString {
            info: info,
            logger_values: logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        try!(write!(f, "{}", self.info.msg()));

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io);

        let res = {
                || -> io::Result<()> {
                    try!(self.logger_values.serialize(self.info, &mut ser));
                    try!(self.info.kv().serialize(self.info, &mut ser));
                    Ok(())
                }
            }()
            .map_err(|_| fmt::Error);

        try!(res);

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))

    }
}

impl slog::Drain for StdLog {
    type Err = io::Error;
    type Ok = ();
    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {

        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
            slog::Level::Warning => log::LogLevel::Warn,
            slog::Level::Info => log::LogLevel::Info,
            slog::Level::Debug => log::LogLevel::Debug,
            slog::Level::Trace => log::LogLevel::Trace,
        };

        let target = info.tag();

        let location = log::LogLocation {
            __module_path: info.module(),
            __file: info.file(),
            __line: info.line(),
        };

        let lazy = LazyLogString::new(info, logger_values);
        // Please don't yell at me for this! :D
        // https://github.com/rust-lang-nursery/log/issues/95
        log::__log(level, target, &location, format_args!("{}", lazy));

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W) -> Self {
        KSV {
            io: io,
        }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> slog::Serializer for KSV<W> {
    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> slog::Result {
        try!(write!(self.io, ", {}: {}", key, val));
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug, Copy)]
pub enum Event {
    /// The size of the window has changed.
    Resized(u32, u32),

    /// The position of the window has changed.
    Moved(i32, i32),

    /// The window has been closed.
    Closed,

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((i32, i32)),

    /// A mouse wheel or touchpad scroll occurred. Depending on whether the
    ///
    /// A positive value indicates that the wheel was rotated forward, away from the user;
    /// a negative value indicates that the wheel was rotated backward, toward the user.
    MouseWheel(MouseScrollDelta),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),

    /// The event loop was woken up by another thread.
    Awakened,

    /// The window needs to be redrawn.
    Refresh,
}

pub type ScanCode = u8;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
    Other(u8),
}

#[derive(Debug, Clone, Copy)]
pub enum MouseScrollDelta {
	/// Amount in lines or rows to scroll in the horizontal
	/// and vertical directions.
	///
	/// Positive values indicate movement forward
	/// (away from the user) or righwards.
	LineDelta(f32, f32),
	/// Amount in pixels to scroll in the horizontal and
	/// vertical direction.
	///
	/// Scroll events are expressed as a PixelDelta if
	/// supported by the device (eg. a touchpad) and
	/// platform.
	PixelDelta(f32, f32)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
    /// The '1' key over the letters.
    Key1,
    /// The '2' key over the letters.
    Key2,
    /// The '3' key over the letters.
    Key3,
    /// The '4' key over the letters.
    Key4,
    /// The '5' key over the letters.
    Key5,
    /// The '6' key over the letters.
    Key6,
    /// The '7' key over the letters.
    Key7,
    /// The '8' key over the letters.
    Key8,
    /// The '9' key over the letters.
    Key9,
    /// The '0' key over the 'O' and 'P' keys.
    Key0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1.
    Escape,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    /// Print Screen/SysRq.
    Snapshot,
    /// Scroll Lock.
    Scroll,
    /// Pause/Break key, next to Scroll lock.
    Pause,

    /// `Insert`, next to Backspace.
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,

    Left,
    Up,
    Right,
    Down,

    /// The Backspace key, right over Enter.
    // TODO: rename
    Back,
    /// The Enter key.
    Return,
    /// The space bar.
    Space,

    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,

    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    Playpause,
    Power,
    Prevtrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    Webback,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen,
}
<commit_msg>Correct typo in MouseScrollDelta docs<commit_after>#[derive(Clone, Debug, Copy)]
pub enum Event {
    /// The size of the window has changed.
    Resized(u32, u32),

    /// The position of the window has changed.
    Moved(i32, i32),

    /// The window has been closed.
    Closed,

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((i32, i32)),

    /// A mouse wheel or touchpad scroll occurred. Depending on whether the
    ///
    /// A positive value indicates that the wheel was rotated forward, away from the user;
    /// a negative value indicates that the wheel was rotated backward, toward the user.
    MouseWheel(MouseScrollDelta),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),

    /// The event loop was woken up by another thread.
    Awakened,

    /// The window needs to be redrawn.
    Refresh,
}

pub type ScanCode = u8;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
    Other(u8),
}

#[derive(Debug, Clone, Copy)]
pub enum MouseScrollDelta {
	/// Amount in lines or rows to scroll in the horizontal
	/// and vertical directions.
	///
	/// Positive values indicate movement forward
	/// (away from the user) or rightwards.
	LineDelta(f32, f32),
	/// Amount in pixels to scroll in the horizontal and
	/// vertical direction.
	///
	/// Scroll events are expressed as a PixelDelta if
	/// supported by the device (eg. a touchpad) and
	/// platform.
	PixelDelta(f32, f32)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
    /// The '1' key over the letters.
    Key1,
    /// The '2' key over the letters.
    Key2,
    /// The '3' key over the letters.
    Key3,
    /// The '4' key over the letters.
    Key4,
    /// The '5' key over the letters.
    Key5,
    /// The '6' key over the letters.
    Key6,
    /// The '7' key over the letters.
    Key7,
    /// The '8' key over the letters.
    Key8,
    /// The '9' key over the letters.
    Key9,
    /// The '0' key over the 'O' and 'P' keys.
    Key0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1.
    Escape,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    /// Print Screen/SysRq.
    Snapshot,
    /// Scroll Lock.
    Scroll,
    /// Pause/Break key, next to Scroll lock.
    Pause,

    /// `Insert`, next to Backspace.
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,

    Left,
    Up,
    Right,
    Down,

    /// The Backspace key, right over Enter.
    // TODO: rename
    Back,
    /// The Enter key.
    Return,
    /// The space bar.
    Space,

    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,

    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    Playpause,
    Power,
    Prevtrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    Webback,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen,
}
<|endoftext|>


<commit_before><commit_msg>Allow for discovering NVMe disks on Linux systems<commit_after><|endoftext|>


<commit_before>extern crate time;

use std::process::Command;
use std::error::Error;
use std::fmt;
use std::io::{Read, Write};
use std::fs::File;

use self::GitRevError::{Git, DateTime, FileIO};

/// Represents different types of errors that may arise when running `gitrev`.
#[derive(Debug)]
pub enum GitRevError {
    /// Invoking `git` command failed.
    Git(String),
    /// Parsing system time failed.
    DateTime(String),
    /// Reading from/writing to a file failed.
    FileIO(String),
}

impl GitRevError {
    /// Print this error and immediately exit program.
    pub fn exit(&self) -> ! {
        println!("{}", self);
        ::std::process::exit(1)
    }
}

impl fmt::Display for GitRevError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Git(ref s) => write!(f, "git error: {}", s),
            DateTime(ref s) => write!(f, "system time error: {}", s),
            FileIO(ref s) => write!(f, "file IO error: {}", s),
        }
    }
}

impl Error for GitRevError {
    fn description(&self) -> &str {
        match *self {
            Git(..) => "git command failed",
            DateTime(..) => "failed to parse system time",
            FileIO(..) => "file input-output error",
        }
    }
}

/// The main gitrev type which takes two arguments:
/// 1) the input filename that is the template, and
/// 2) the output filename that will be generated
#[derive(Clone, Debug)]
pub struct GitRev {
    template_filename: String,
    generated_filename: String,
}

impl GitRev {
    pub fn new(template_filename: &str, generated_filename: &str) -> GitRev {
        GitRev {
            template_filename: String::from(template_filename),
            generated_filename: String::from(generated_filename),
        }
    }

    /// Generates the output file with `SubWCRev.exe` keywords
    /// substituted for `git` command equivalents.
    ///
    /// The process consists of the following steps:
    /// 1) get all the necessary data from git
    /// 2) read in the contents of the template file
    /// 3) parse the contents and replace all special keywords with git data
    /// 4) write the contents to the output file
    pub fn generate_from_template(&self) -> Result<(), GitRevError> {
        // Get all the necessary data from git and system
        let curr_rev = try!(self.git_command("describe --always"));
        let curr_branch = try!(self.git_command("rev-parse --abbrev-ref HEAD"));
        let remote_url = try!(self.git_command("config --get remote.origin.url"));
        let build_time = try!(self.build_time());
        println!("Current revision: {}", curr_rev);
        println!("Build time: {}", build_time);
        println!("Current branch: {}", curr_branch);
        println!("Remote url: {}", remote_url);

        // Read in contents of the template file
        let mut contents = try!(self.read_in_template_file());

        // Parse the contents in search of special delimiters
        // and replace with the git data
        contents = contents.replace("$WCREV$", &curr_rev)
                           .replace("$WCNOW$", &build_time)
                           .replace("$WCURL$", &remote_url);

        // Write contents to the destination file
        self.write_to_dst_file(&contents)
    }

    fn git_command(&self, cmd: &str) -> Result<String, GitRevError> {
        // Parse args
        let args: Vec<&str> = cmd.split_whitespace().collect();
        let output = match Command::new("git").args(&args).output() {
            Err(e) => return Err(Git(String::from(e.description()))),
            Ok(out) => out,
        };
        if output.stdout.is_empty() {
            let err_msg = String::from_utf8_lossy(&output.stderr);
            return Err(Git(String::from(err_msg.trim())));
        }
        let result = String::from_utf8_lossy(&output.stdout);
        Ok(String::from(result.trim()))
    }

    fn build_time(&self) -> Result<String, GitRevError> {
        match time::strftime("%F %T %Z", &time::now_utc()) {
            Err(e) => Err(DateTime(String::from(e.description()))),
            Ok(out) => Ok(out),
        }
    }

    fn read_in_template_file(&self) -> Result<String, GitRevError> {
        let mut f = match File::open(&self.template_filename) {
            Err(e) => return Err(FileIO(String::from(e.description()))),
            Ok(f) => f,
        };
        let mut contents = String::new();
        match f.read_to_string(&mut contents) {
            Err(e) => return Err(FileIO(String::from(e.description()))),
            Ok(_) => (),
        };
        Ok(contents)
    }

    fn write_to_dst_file(&self, contents: &str) -> Result<(), GitRevError> {
        let mut f = match File::create(&self.generated_filename) {
            Err(e) => return Err(FileIO(String::from(e.description()))),
            Ok(f) => f,
        };
        match f.write_all(contents.as_bytes()) {
            Err(e) => Err(FileIO(String::from(e.description()))),
            Ok(()) => Ok(()),
        }
    }
}
<commit_msg>Use tag if branch is master; otherwise use branch<commit_after>extern crate time;

use std::process::Command;
use std::error::Error;
use std::fmt;
use std::io::{Read, Write};
use std::fs::File;

use self::GitRevError::{Git, DateTime, FileIO};

/// Represents different types of errors that may arise when running `gitrev`.
#[derive(Debug)]
pub enum GitRevError {
    /// Invoking `git` command failed.
    Git(String),
    /// Parsing system time failed.
    DateTime(String),
    /// Reading from/writing to a file failed.
    FileIO(String),
}

impl GitRevError {
    /// Print this error and immediately exit program.
    pub fn exit(&self) -> ! {
        println!("{}", self);
        ::std::process::exit(1)
    }
}

impl fmt::Display for GitRevError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Git(ref s) => write!(f, "git error: {}", s),
            DateTime(ref s) => write!(f, "system time error: {}", s),
            FileIO(ref s) => write!(f, "file IO error: {}", s),
        }
    }
}

impl Error for GitRevError {
    fn description(&self) -> &str {
        match *self {
            Git(..) => "git command failed",
            DateTime(..) => "failed to parse system time",
            FileIO(..) => "file input-output error",
        }
    }
}

/// The main gitrev type which takes two arguments:
/// 1) the input filename that is the template, and
/// 2) the output filename that will be generated
#[derive(Clone, Debug)]
pub struct GitRev {
    template_filename: String,
    generated_filename: String,
}

impl GitRev {
    pub fn new(template_filename: &str, generated_filename: &str) -> GitRev {
        GitRev {
            template_filename: String::from(template_filename),
            generated_filename: String::from(generated_filename),
        }
    }

    /// Generates the output file with `SubWCRev.exe` keywords
    /// substituted for `git` command equivalents.
    ///
    /// The process consists of the following steps:
    /// 1) get all the necessary data from git
    /// 2) read in the contents of the template file
    /// 3) parse the contents and replace all special keywords with git data
    /// 4) write the contents to the output file
    pub fn generate_from_template(&self) -> Result<(), GitRevError> {
        // Get all the necessary data from git and system
        let curr_rev = try!(self.git_command("describe --always"));
        let curr_branch = try!(self.git_command("rev-parse --abbrev-ref HEAD"));
        let remote_url = try!(self.git_command("config --get remote.origin.url"));
        let build_time = try!(self.build_time());
        println!("Current revision: {}", curr_rev);
        println!("Build time: {}", build_time);
        println!("Current branch: {}", curr_branch);
        println!("Remote url: {}", remote_url);

        // Read in contents of the template file
        let mut contents = try!(self.read_in_template_file());

        // Parse the contents in search of special delimiters
        // and replace with the git data
        // here, we decide whether to use current tag or branch
        // in place of WCREV token
        let build = if curr_branch == "master" { curr_rev } else { curr_branch };
        contents = contents.replace("$WCREV$", &build)
                           .replace("$WCNOW$", &build_time)
                           .replace("$WCURL$", &remote_url);

        // Write contents to the destination file
        self.write_to_dst_file(&contents)
    }

    fn git_command(&self, cmd: &str) -> Result<String, GitRevError> {
        // Parse args
        let args: Vec<&str> = cmd.split_whitespace().collect();
        let output = match Command::new("git").args(&args).output() {
            Err(e) => return Err(Git(String::from(e.description()))),
            Ok(out) => out,
        };
        if output.stdout.is_empty() {
            let err_msg = String::from_utf8_lossy(&output.stderr);
            return Err(Git(String::from(err_msg.trim())));
        }
        let result = String::from_utf8_lossy(&output.stdout);
        Ok(String::from(result.trim()))
    }

    fn build_time(&self) -> Result<String, GitRevError> {
        match time::strftime("%F %T %Z", &time::now_utc()) {
            Err(e) => Err(DateTime(String::from(e.description()))),
            Ok(out) => Ok(out),
        }
    }

    fn read_in_template_file(&self) -> Result<String, GitRevError> {
        let mut f = match File::open(&self.template_filename) {
            Err(e) => return Err(FileIO(String::from(e.description()))),
            Ok(f) => f,
        };
        let mut contents = String::new();
        match f.read_to_string(&mut contents) {
            Err(e) => return Err(FileIO(String::from(e.description()))),
            Ok(_) => (),
        };
        Ok(contents)
    }

    fn write_to_dst_file(&self, contents: &str) -> Result<(), GitRevError> {
        let mut f = match File::create(&self.generated_filename) {
            Err(e) => return Err(FileIO(String::from(e.description()))),
            Ok(f) => f,
        };
        match f.write_all(contents.as_bytes()) {
            Err(e) => Err(FileIO(String::from(e.description()))),
            Ok(()) => Ok(()),
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A timer thread that gives the painting task a little time to catch up when the user scrolls.

use compositor_task::{CompositorProxy, Msg};

use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread::{Builder, sleep_ms};
use time;

/// The amount of time in nanoseconds that we give to the painting thread to paint new tiles upon
/// processing a scroll event that caused new tiles to be revealed. When this expires, we give up
/// and composite anyway (showing a "checkerboard") to avoid dropping the frame.
static TIMEOUT: i64 = 12_000_000;

pub struct ScrollingTimerProxy {
    sender: Sender<ToScrollingTimerMsg>,
}

pub struct ScrollingTimer {
    compositor_proxy: Box<CompositorProxy>,
    receiver: Receiver<ToScrollingTimerMsg>,
}

enum ToScrollingTimerMsg {
    ExitMsg,
    ScrollEventProcessedMsg(u64),
}

impl ScrollingTimerProxy {
    pub fn new(compositor_proxy: Box<CompositorProxy+Send>) -> ScrollingTimerProxy {
        let (to_scrolling_timer_sender, to_scrolling_timer_receiver) = channel();
        Builder::new().spawn(move || {
            let mut scrolling_timer = ScrollingTimer {
                compositor_proxy: compositor_proxy,
                receiver: to_scrolling_timer_receiver,
            };
            scrolling_timer.run();
        }).unwrap();
        ScrollingTimerProxy {
            sender: to_scrolling_timer_sender,
        }
    }

    pub fn scroll_event_processed(&mut self, timestamp: u64) {
        self.sender.send(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)).unwrap()
    }

    pub fn shutdown(&mut self) {
        self.sender.send(ToScrollingTimerMsg::ExitMsg).unwrap()
    }
}

impl ScrollingTimer {
    pub fn run(&mut self) {
        loop {
            match self.receiver.recv() {
                Ok(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)) => {
                    let target = timestamp as i64 + TIMEOUT;
                    let delta_ns = target - (time::precise_time_ns() as i64);
                    sleep_ms((delta_ns / 1000) as u32);
                    self.compositor_proxy.send(Msg::ScrollTimeout(timestamp));
                }
                Ok(ToScrollingTimerMsg::ExitMsg) | Err(_) => break,
            }
        }
    }
}

<commit_msg>Auto merge of #6011 - pcwalton:ns_to_ms, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A timer thread that gives the painting task a little time to catch up when the user scrolls.

use compositor_task::{CompositorProxy, Msg};

use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread::{Builder, sleep_ms};
use time;

/// The amount of time in nanoseconds that we give to the painting thread to paint new tiles upon
/// processing a scroll event that caused new tiles to be revealed. When this expires, we give up
/// and composite anyway (showing a "checkerboard") to avoid dropping the frame.
static TIMEOUT: i64 = 12_000_000;

pub struct ScrollingTimerProxy {
    sender: Sender<ToScrollingTimerMsg>,
}

pub struct ScrollingTimer {
    compositor_proxy: Box<CompositorProxy>,
    receiver: Receiver<ToScrollingTimerMsg>,
}

enum ToScrollingTimerMsg {
    ExitMsg,
    ScrollEventProcessedMsg(u64),
}

impl ScrollingTimerProxy {
    pub fn new(compositor_proxy: Box<CompositorProxy+Send>) -> ScrollingTimerProxy {
        let (to_scrolling_timer_sender, to_scrolling_timer_receiver) = channel();
        Builder::new().spawn(move || {
            let mut scrolling_timer = ScrollingTimer {
                compositor_proxy: compositor_proxy,
                receiver: to_scrolling_timer_receiver,
            };
            scrolling_timer.run();
        }).unwrap();
        ScrollingTimerProxy {
            sender: to_scrolling_timer_sender,
        }
    }

    pub fn scroll_event_processed(&mut self, timestamp: u64) {
        self.sender.send(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)).unwrap()
    }

    pub fn shutdown(&mut self) {
        self.sender.send(ToScrollingTimerMsg::ExitMsg).unwrap()
    }
}

impl ScrollingTimer {
    pub fn run(&mut self) {
        loop {
            match self.receiver.recv() {
                Ok(ToScrollingTimerMsg::ScrollEventProcessedMsg(timestamp)) => {
                    let target = timestamp as i64 + TIMEOUT;
                    let delta_ns = target - (time::precise_time_ns() as i64);
                    sleep_ms((delta_ns / 1000000) as u32);
                    self.compositor_proxy.send(Msg::ScrollTimeout(timestamp));
                }
                Ok(ToScrollingTimerMsg::ExitMsg) | Err(_) => break,
            }
        }
    }
}

<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::str::Words;
use std::io::{
  BufferedReader,
  File
};
use gl::types::GLfloat;
use cgmath::vector::{
  Vec3,
  Vec2,
};

struct Face {
  vertex: [int, ..3],
  texture: [int, ..3],
  normal: [int, ..3],
}

pub struct Model {
  coords: ~[Vec3<GLfloat>],
  normals: ~[Vec3<GLfloat>],
  texture_coords: ~[Vec2<GLfloat>],
  faces: ~[Face],
}

// TODO: unwrap() -> ...
impl Model {
  pub fn new(filename: &str) -> Model {
    let mut obj = Model {
      coords: ~[],
      normals: ~[],
      texture_coords: ~[],
      faces: ~[],
    };
    obj.read(filename);
    obj
  }

  fn read_v_or_vn(words: &mut Words) -> Vec3<GLfloat> {
    Vec3 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: from_str(words.next().unwrap()).unwrap(),
      z: from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_vt(words: &mut Words) -> Vec2<GLfloat> {
    // TODO: y = 1.0 - y; // flip vertically
    Vec2 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: 1.0 - from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_f(words: &mut Words) -> Face {
    let mut face = Face {
      vertex: [0, 0, 0],
      texture: [0, 0, 0],
      normal: [0, 0, 0],
    };
    let mut i = 0;
    for group in *words {
      let mut w = group.split('/');
      face.vertex[i] = from_str(w.next().unwrap()).unwrap();
      face.texture[i] = from_str(w.next().unwrap()).unwrap();
      face.normal[i] = from_str(w.next().unwrap()).unwrap();
      i += 1;
    }
    face
  }

  fn read_line(&mut self, line: &str) {
    let mut words = line.words();
    fn is_correct_tag(tag: &str) -> bool {
      tag.len() != 0 && tag[0] != ('#' as u8)
    }
    match words.next() {
      Some(tag) if is_correct_tag(tag) => {
        let w = &mut words;
        match tag {
          &"v" => self.coords.push(Model::read_v_or_vn(w)),
          &"vn" => self.normals.push(Model::read_v_or_vn(w)),
          &"vt" => self.texture_coords.push(Model::read_vt(w)),
          &"f" => self.faces.push(Model::read_f(w)),
          _ => {},
        }
      }
      _ => {},
    };
  }

  fn read(&mut self, filename: &str) {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
      self.read_line(line);
    }
  }

  pub fn build(&self) -> ~[Vec3<GLfloat>]{
    let mut mesh = ~[];
    for face in self.faces.iter() {
      for i in range(0, 3) {
        let vertex_id = face.vertex[i] - 1;
        mesh.push(self.coords[vertex_id]);
      }
    }
    mesh
  }

  pub fn build_tex_coord(&self) -> ~[Vec2<GLfloat>]{
    let mut tex_coords = ~[];
    for face in self.faces.iter() {
      for i in range(0, 3) {
        let texture_coord_id = face.texture[i] - 1;
        tex_coords.push(self.texture_coords[texture_coord_id]);
      }
    }
    tex_coords
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>obj.rs: Removed outdated TODO<commit_after>// See LICENSE file for copyright and license details.

use std::str::Words;
use std::io::{
  BufferedReader,
  File
};
use gl::types::GLfloat;
use cgmath::vector::{
  Vec3,
  Vec2,
};

struct Face {
  vertex: [int, ..3],
  texture: [int, ..3],
  normal: [int, ..3],
}

pub struct Model {
  coords: ~[Vec3<GLfloat>],
  normals: ~[Vec3<GLfloat>],
  texture_coords: ~[Vec2<GLfloat>],
  faces: ~[Face],
}

// TODO: unwrap() -> ...
impl Model {
  pub fn new(filename: &str) -> Model {
    let mut obj = Model {
      coords: ~[],
      normals: ~[],
      texture_coords: ~[],
      faces: ~[],
    };
    obj.read(filename);
    obj
  }

  fn read_v_or_vn(words: &mut Words) -> Vec3<GLfloat> {
    Vec3 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: from_str(words.next().unwrap()).unwrap(),
      z: from_str(words.next().unwrap()).unwrap(),
    }
  }

  fn read_vt(words: &mut Words) -> Vec2<GLfloat> {
    Vec2 {
      x: from_str(words.next().unwrap()).unwrap(),
      y: 1.0 - from_str(words.next().unwrap()).unwrap(), // flip
    }
  }

  fn read_f(words: &mut Words) -> Face {
    let mut face = Face {
      vertex: [0, 0, 0],
      texture: [0, 0, 0],
      normal: [0, 0, 0],
    };
    let mut i = 0;
    for group in *words {
      let mut w = group.split('/');
      face.vertex[i] = from_str(w.next().unwrap()).unwrap();
      face.texture[i] = from_str(w.next().unwrap()).unwrap();
      face.normal[i] = from_str(w.next().unwrap()).unwrap();
      i += 1;
    }
    face
  }

  fn read_line(&mut self, line: &str) {
    let mut words = line.words();
    fn is_correct_tag(tag: &str) -> bool {
      tag.len() != 0 && tag[0] != ('#' as u8)
    }
    match words.next() {
      Some(tag) if is_correct_tag(tag) => {
        let w = &mut words;
        match tag {
          &"v" => self.coords.push(Model::read_v_or_vn(w)),
          &"vn" => self.normals.push(Model::read_v_or_vn(w)),
          &"vt" => self.texture_coords.push(Model::read_vt(w)),
          &"f" => self.faces.push(Model::read_f(w)),
          _ => {},
        }
      }
      _ => {},
    };
  }

  fn read(&mut self, filename: &str) {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
      self.read_line(line);
    }
  }

  pub fn build(&self) -> ~[Vec3<GLfloat>]{
    let mut mesh = ~[];
    for face in self.faces.iter() {
      for i in range(0, 3) {
        let vertex_id = face.vertex[i] - 1;
        mesh.push(self.coords[vertex_id]);
      }
    }
    mesh
  }

  pub fn build_tex_coord(&self) -> ~[Vec2<GLfloat>]{
    let mut tex_coords = ~[];
    for face in self.faces.iter() {
      for i in range(0, 3) {
        let texture_coord_id = face.texture[i] - 1;
        tex_coords.push(self.texture_coords[texture_coord_id]);
      }
    }
    tex_coords
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::partial_string::*;
use crate::parser::ast::*;
use crate::types::*;

use ordered_float::OrderedFloat;
use rug::{Integer, Rational};

use std::convert::TryFrom;

pub(crate) type Heap = Vec<HeapCellValue>;

impl From<Literal> for HeapCellValue {
    #[inline]
    fn from(literal: Literal) -> Self {
        match literal {
            Literal::Atom(name) => atom_as_cell!(name),
            Literal::Char(c) => char_as_cell!(c),
            Literal::Fixnum(n) => fixnum_as_cell!(n),
            Literal::Integer(bigint_ptr) => {
                typed_arena_ptr_as_cell!(bigint_ptr)
            }
            Literal::Rational(bigint_ptr) => {
                typed_arena_ptr_as_cell!(bigint_ptr)
            }
            Literal::Float(f) => HeapCellValue::from(f),
            Literal::String(s) => {
                if s == atom!("") {
                    empty_list_as_cell!()
                } else {
                    string_as_cstr_cell!(s)
                }
            }
        }
    }
}

impl TryFrom<HeapCellValue> for Literal {
    type Error = ();

    fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
        read_heap_cell!(value,
            (HeapCellValueTag::Atom, (name, arity)) => {
                if arity == 0 {
                    Ok(Literal::Atom(name))
                } else {
                    Err(())
                }
            }
            (HeapCellValueTag::Char, c) => {
                Ok(Literal::Char(c))
            }
            (HeapCellValueTag::Fixnum, n) => {
                Ok(Literal::Fixnum(n))
            }
            (HeapCellValueTag::F64, f) => {
                Ok(Literal::Float(f))
            }
            (HeapCellValueTag::Cons, cons_ptr) => {
                match_untyped_arena_ptr!(cons_ptr,
                     (ArenaHeaderTag::Integer, n) => {
                         Ok(Literal::Integer(n))
                     }
                     (ArenaHeaderTag::Rational, n) => {
                         Ok(Literal::Rational(n))
                     }
                     (ArenaHeaderTag::F64, f) => {
                         // remove this redundancy.
                         Ok(Literal::Float(F64Ptr(f)))
                     }
                     _ => {
                         Err(())
                     }
                )
            }
            (HeapCellValueTag::CStr, cstr_atom) => {
                Ok(Literal::String(cstr_atom))
            }
            _ => {
                Err(())
            }
        )
    }
}

// sometimes we need to dereference variables that are found only in
// the heap without access to the full WAM (e.g., while detecting
// cycles in terms), and which therefore may only point other cells in
// the heap (thanks to the design of the WAM).
pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
    loop {
        let new_value = read_heap_cell!(value,
            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                heap[h]
            }
            _ => {
                value
            }
        );

        if new_value != value && new_value.is_var() {
            value = new_value;
            continue;
        }

        return value;
    }
}

pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
    read_heap_cell!(value,
        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
            heap[h]
        }
        _ => {
            value
        }
    )
}

#[allow(dead_code)]
pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
    for (index, term) in heap.enumerate() {
        println!("{} : {:?}", h + index, term);
    }
}

#[inline]
pub(crate) fn put_complete_string(
    heap: &mut Heap,
    s: &str,
    atom_tbl: &mut AtomTable,
) -> HeapCellValue {
    match allocate_pstr(heap, s, atom_tbl) {
        Some(h) => {
            heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.

            if heap.len() == h + 1 {
                let pstr_atom = cell_as_atom!(heap[h]);
                heap[h] = atom_as_cstr_cell!(pstr_atom);
                heap_loc_as_cell!(h)
            } else {
                heap.push(empty_list_as_cell!());
                pstr_loc_as_cell!(h)
            }
        }
        None => {
            empty_list_as_cell!()
        }
    }
}

#[inline]
pub(crate) fn put_partial_string(
    heap: &mut Heap,
    s: &str,
    atom_tbl: &mut AtomTable,
) -> HeapCellValue {
    match allocate_pstr(heap, s, atom_tbl) {
        Some(h) => {
            pstr_loc_as_cell!(h)
        }
        None => {
            empty_list_as_cell!()
        }
    }
}

#[inline]
pub(crate) fn allocate_pstr(
    heap: &mut Heap,
    mut src: &str,
    atom_tbl: &mut AtomTable,
) -> Option<usize> {
    let orig_h = heap.len();

    loop {
        if src == "" {
            return if orig_h == heap.len() {
                None
            } else {
                let tail_h = heap.len() - 1;
                heap[tail_h] = heap_loc_as_cell!(tail_h);

                Some(orig_h)
            };
        }

        let h = heap.len();

        let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
            Some(tuple) => tuple,
            None => {
                if src.len() > '\u{0}'.len_utf8() {
                    src = &src['\u{0}'.len_utf8()..];
                    continue;
                } else if orig_h == h {
                    return None;
                } else {
                    heap[h - 1] = heap_loc_as_cell!(h - 1);
                    return Some(orig_h);
                }
            }
        };

        heap.push(string_as_pstr_cell!(pstr));

        if rest_src != "" {
            heap.push(pstr_loc_as_cell!(h + 2));
            src = rest_src;
        } else {
            heap.push(heap_loc_as_cell!(h + 1));
            return Some(orig_h);
        }
    }
}

pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
    heap: &mut Heap,
    values: impl Iterator<Item = SrcT>,
    filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
) -> usize {
    let head_addr = heap.len();
    let mut h = head_addr;

    for value in values {
        let value = value.into();

        if filter_fn(heap, value) {
            heap.push(list_loc_as_cell!(h + 1));
            heap.push(value);

            h += 2;
        }
    }

    heap.push(empty_list_as_cell!());

    head_addr
}

#[inline(always)]
pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
where
    Iter: Iterator<Item = SrcT>,
    SrcT: Into<HeapCellValue>,
{
    filtered_iter_to_heap_list(heap, values, |_, _| true)
}

pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
    let extract_integer = |s: usize| -> Option<usize> {
        match Number::try_from(heap[s]) {
            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
            Ok(Number::Integer(n)) => n.to_usize(),
            _ => None,
        }
    };

    read_heap_cell!(addr,
        (HeapCellValueTag::Str, s) => {
            let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();

            if name == atom!("dir_entry") && arity == 1 {
                extract_integer(s+1)
            } else {
                panic!(
                    "to_local_code_ptr crashed with p.i. {}/{}",
                    name.as_str(),
                    arity,
                );
            }
        }
        _ => {
            None
        }
    )
}
<commit_msg>put_complete_string should push the empty list to the heap for empty strings (#1209)<commit_after>use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::partial_string::*;
use crate::parser::ast::*;
use crate::types::*;

use ordered_float::OrderedFloat;
use rug::{Integer, Rational};

use std::convert::TryFrom;

pub(crate) type Heap = Vec<HeapCellValue>;

impl From<Literal> for HeapCellValue {
    #[inline]
    fn from(literal: Literal) -> Self {
        match literal {
            Literal::Atom(name) => atom_as_cell!(name),
            Literal::Char(c) => char_as_cell!(c),
            Literal::Fixnum(n) => fixnum_as_cell!(n),
            Literal::Integer(bigint_ptr) => {
                typed_arena_ptr_as_cell!(bigint_ptr)
            }
            Literal::Rational(bigint_ptr) => {
                typed_arena_ptr_as_cell!(bigint_ptr)
            }
            Literal::Float(f) => HeapCellValue::from(f),
            Literal::String(s) => {
                if s == atom!("") {
                    empty_list_as_cell!()
                } else {
                    string_as_cstr_cell!(s)
                }
            }
        }
    }
}

impl TryFrom<HeapCellValue> for Literal {
    type Error = ();

    fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
        read_heap_cell!(value,
            (HeapCellValueTag::Atom, (name, arity)) => {
                if arity == 0 {
                    Ok(Literal::Atom(name))
                } else {
                    Err(())
                }
            }
            (HeapCellValueTag::Char, c) => {
                Ok(Literal::Char(c))
            }
            (HeapCellValueTag::Fixnum, n) => {
                Ok(Literal::Fixnum(n))
            }
            (HeapCellValueTag::F64, f) => {
                Ok(Literal::Float(f))
            }
            (HeapCellValueTag::Cons, cons_ptr) => {
                match_untyped_arena_ptr!(cons_ptr,
                     (ArenaHeaderTag::Integer, n) => {
                         Ok(Literal::Integer(n))
                     }
                     (ArenaHeaderTag::Rational, n) => {
                         Ok(Literal::Rational(n))
                     }
                     (ArenaHeaderTag::F64, f) => {
                         // remove this redundancy.
                         Ok(Literal::Float(F64Ptr(f)))
                     }
                     _ => {
                         Err(())
                     }
                )
            }
            (HeapCellValueTag::CStr, cstr_atom) => {
                Ok(Literal::String(cstr_atom))
            }
            _ => {
                Err(())
            }
        )
    }
}

// sometimes we need to dereference variables that are found only in
// the heap without access to the full WAM (e.g., while detecting
// cycles in terms), and which therefore may only point other cells in
// the heap (thanks to the design of the WAM).
pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
    loop {
        let new_value = read_heap_cell!(value,
            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
                heap[h]
            }
            _ => {
                value
            }
        );

        if new_value != value && new_value.is_var() {
            value = new_value;
            continue;
        }

        return value;
    }
}

pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
    read_heap_cell!(value,
        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
            heap[h]
        }
        _ => {
            value
        }
    )
}

#[allow(dead_code)]
pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
    for (index, term) in heap.enumerate() {
        println!("{} : {:?}", h + index, term);
    }
}

#[inline]
pub(crate) fn put_complete_string(
    heap: &mut Heap,
    s: &str,
    atom_tbl: &mut AtomTable,
) -> HeapCellValue {
    match allocate_pstr(heap, s, atom_tbl) {
        Some(h) => {
            heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.

            if heap.len() == h + 1 {
                let pstr_atom = cell_as_atom!(heap[h]);
                heap[h] = atom_as_cstr_cell!(pstr_atom);
                heap_loc_as_cell!(h)
            } else {
                heap.push(empty_list_as_cell!());
                pstr_loc_as_cell!(h)
            }
        }
        None => {
            let h = heap.len();
            heap.push(empty_list_as_cell!());
            heap_loc_as_cell!(h)
        }
    }
}

#[inline]
pub(crate) fn put_partial_string(
    heap: &mut Heap,
    s: &str,
    atom_tbl: &mut AtomTable,
) -> HeapCellValue {
    match allocate_pstr(heap, s, atom_tbl) {
        Some(h) => {
            pstr_loc_as_cell!(h)
        }
        None => {
            empty_list_as_cell!()
        }
    }
}

#[inline]
pub(crate) fn allocate_pstr(
    heap: &mut Heap,
    mut src: &str,
    atom_tbl: &mut AtomTable,
) -> Option<usize> {
    let orig_h = heap.len();

    loop {
        if src == "" {
            return if orig_h == heap.len() {
                None
            } else {
                let tail_h = heap.len() - 1;
                heap[tail_h] = heap_loc_as_cell!(tail_h);

                Some(orig_h)
            };
        }

        let h = heap.len();

        let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
            Some(tuple) => tuple,
            None => {
                if src.len() > '\u{0}'.len_utf8() {
                    src = &src['\u{0}'.len_utf8()..];
                    continue;
                } else if orig_h == h {
                    return None;
                } else {
                    heap[h - 1] = heap_loc_as_cell!(h - 1);
                    return Some(orig_h);
                }
            }
        };

        heap.push(string_as_pstr_cell!(pstr));

        if rest_src != "" {
            heap.push(pstr_loc_as_cell!(h + 2));
            src = rest_src;
        } else {
            heap.push(heap_loc_as_cell!(h + 1));
            return Some(orig_h);
        }
    }
}

pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
    heap: &mut Heap,
    values: impl Iterator<Item = SrcT>,
    filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
) -> usize {
    let head_addr = heap.len();
    let mut h = head_addr;

    for value in values {
        let value = value.into();

        if filter_fn(heap, value) {
            heap.push(list_loc_as_cell!(h + 1));
            heap.push(value);

            h += 2;
        }
    }

    heap.push(empty_list_as_cell!());

    head_addr
}

#[inline(always)]
pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
where
    Iter: Iterator<Item = SrcT>,
    SrcT: Into<HeapCellValue>,
{
    filtered_iter_to_heap_list(heap, values, |_, _| true)
}

pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
    let extract_integer = |s: usize| -> Option<usize> {
        match Number::try_from(heap[s]) {
            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
            Ok(Number::Integer(n)) => n.to_usize(),
            _ => None,
        }
    };

    read_heap_cell!(addr,
        (HeapCellValueTag::Str, s) => {
            let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();

            if name == atom!("dir_entry") && arity == 1 {
                extract_integer(s+1)
            } else {
                panic!(
                    "to_local_code_ptr crashed with p.i. {}/{}",
                    name.as_str(),
                    arity,
                );
            }
        }
        _ => {
            None
        }
    )
}
<|endoftext|>