<commit_before>/*!
The types module provides a way of associating glob patterns on file names to
file types.
*/

use std::collections::HashMap;
use std::error::Error as StdError;
use std::fmt;
use std::path::Path;

use regex;

use gitignore::{Match, Pattern};
use glob::{self, MatchOptions};

const TYPE_EXTENSIONS: &'static [(&'static str, &'static [&'static str])] = &[
    ("asm", &["*.asm", "*.s", "*.S"]),
    ("awk", &["*.awk"]),
    ("c", &["*.c", "*.h", "*.H"]),
    ("cbor", &["*.cbor"]),
    ("clojure", &["*.clj", "*.cljs"]),
    ("cmake", &["CMakeLists.txt"]),
    ("coffeescript", &["*.coffee"]),
    ("cpp", &[
        "*.C", "*.cc", "*.cpp", "*.cxx",
        "*.h", "*.H", "*.hh", "*.hpp",
    ]),
    ("csharp", &["*.cs"]),
    ("css", &["*.css"]),
    ("cython", &["*.pyx"]),
    ("dart", &["*.dart"]),
    ("d", &["*.d"]),
    ("elisp", &["*.el"]),
    ("erlang", &["*.erl", "*.hrl"]),
    ("fortran", &[
        "*.f", "*.F", "*.f77", "*.F77", "*.pfo",
        "*.f90", "*.F90", "*.f95", "*.F95",
    ]),
    ("go", &["*.go"]),
    ("groovy", &["*.groovy"]),
    ("haskell", &["*.hs", "*.lhs"]),
    ("html", &["*.htm", "*.html"]),
    ("java", &["*.java"]),
    ("js", &["*.js"]),
    ("json", &["*.json"]),
    ("jsonl", &["*.jsonl"]),
    ("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
    ("lua", &["*.lua"]),
    ("m4", &["*.ac", "*.m4"]),
    ("make", &["gnumakefile", "Gnumakefile", "makefile", "Makefile", "*.mk"]),
    ("markdown", &["*.md"]),
    ("matlab", &["*.m"]),
    ("mk", &["mkfile"]),
    ("ml", &["*.ml"]),
    ("objc", &["*.h", "*.m"]),
    ("objcpp", &["*.h", "*.mm"]),
    ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
    ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm"]),
    ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
    ("py", &["*.py"]),
    ("readme", &["README*", "*README"]),
    ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
    ("rst", &["*.rst"]),
    ("ruby", &["*.rb"]),
    ("rust", &["*.rs"]),
    ("scala", &["*.scala"]),
    ("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
    ("sql", &["*.sql"]),
    ("tex", &["*.tex", "*.cls", "*.sty"]),
    ("txt", &["*.txt"]),
    ("toml", &["*.toml", "Cargo.lock"]),
    ("vala", &["*.vala"]),
    ("vb", &["*.vb"]),
    ("vimscript", &["*.vim"]),
    ("xml", &["*.xml"]),
    ("yacc", &["*.y"]),
    ("yaml", &["*.yaml", "*.yml"]),
];

/// Describes all the possible failure conditions for building a file type
/// matcher.
#[derive(Debug)]
pub enum Error {
    /// We tried to select (or negate) a file type that is not defined.
    UnrecognizedFileType(String),
    /// A user specified file type definition could not be parsed.
    InvalidDefinition,
    /// There was an error building the matcher (probably a bad glob).
    Glob(glob::Error),
    /// There was an error compiling a glob as a regex.
    Regex(regex::Error),
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::UnrecognizedFileType(_) => "unrecognized file type",
            Error::InvalidDefinition => "invalid definition",
            Error::Glob(ref err) => err.description(),
            Error::Regex(ref err) => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::UnrecognizedFileType(ref ty) => {
                write!(f, "unrecognized file type: {}", ty)
            }
            Error::InvalidDefinition => {
                write!(f, "invalid definition (format is type:glob, e.g., \
                           html:*.html)")
            }
            Error::Glob(ref err) => err.fmt(f),
            Error::Regex(ref err) => err.fmt(f),
        }
    }
}

impl From<glob::Error> for Error {
    fn from(err: glob::Error) -> Error {
        Error::Glob(err)
    }
}

impl From<regex::Error> for Error {
    fn from(err: regex::Error) -> Error {
        Error::Regex(err)
    }
}

/// A single file type definition.
#[derive(Clone, Debug)]
pub struct FileTypeDef {
    name: String,
    pats: Vec<String>,
}

impl FileTypeDef {
    /// Return the name of this file type.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Return the glob patterns used to recognize this file type.
    pub fn patterns(&self) -> &[String] {
        &self.pats
    }
}

/// Types is a file type matcher.
#[derive(Clone, Debug)]
pub struct Types {
    selected: Option<glob::SetYesNo>,
    negated: Option<glob::SetYesNo>,
    has_selected: bool,
    unmatched_pat: Pattern,
}

impl Types {
    /// Creates a new file type matcher from the given Gitignore matcher. If
    /// not Gitignore matcher is provided, then the file type matcher has no
    /// effect.
    ///
    /// If has_selected is true, then at least one file type was selected.
    /// Therefore, any non-matches should be ignored.
    fn new(
        selected: Option<glob::SetYesNo>,
        negated: Option<glob::SetYesNo>,
        has_selected: bool,
    ) -> Types {
        Types {
            selected: selected,
            negated: negated,
            has_selected: has_selected,
            unmatched_pat: Pattern {
                from: Path::new("<filetype>").to_path_buf(),
                original: "<N/A>".to_string(),
                pat: "<N/A>".to_string(),
                whitelist: false,
                only_dir: false,
            },
        }
    }

    /// Creates a new file type matcher that never matches.
    pub fn empty() -> Types {
        Types::new(None, None, false)
    }

    /// Returns a match for the given path against this file type matcher.
    ///
    /// The path is considered whitelisted if it matches a selected file type.
    /// The path is considered ignored if it matched a negated file type.
    /// If at least one file type is selected and path doesn't match, then
    /// the path is also considered ignored.
    pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
        // If we don't have any matcher, then we can't do anything.
        if self.negated.is_none() && self.selected.is_none() {
            return Match::None;
        }
        // File types don't apply to directories.
        if is_dir {
            return Match::None;
        }
        let path = path.as_ref();
        let name = match path.file_name() {
            Some(name) => name.to_string_lossy(),
            None if self.has_selected => {
                return Match::Ignored(&self.unmatched_pat);
            }
            None => {
                return Match::None;
            }
        };
        if self.negated.as_ref().map(|s| s.is_match(&*name)).unwrap_or(false) {
            return Match::Ignored(&self.unmatched_pat);
        }
        if self.selected.as_ref().map(|s|s.is_match(&*name)).unwrap_or(false) {
            return Match::Whitelist(&self.unmatched_pat);
        }
        if self.has_selected {
            Match::Ignored(&self.unmatched_pat)
        } else {
            Match::None
        }
    }
}

/// TypesBuilder builds a type matcher from a set of file type definitions and
/// a set of file type selections.
pub struct TypesBuilder {
    types: HashMap<String, Vec<String>>,
    selected: Vec<String>,
    negated: Vec<String>,
}

impl TypesBuilder {
    /// Create a new builder for a file type matcher.
    pub fn new() -> TypesBuilder {
        TypesBuilder {
            types: HashMap::new(),
            selected: vec![],
            negated: vec![],
        }
    }

    /// Build the current set of file type definitions *and* selections into
    /// a file type matcher.
    pub fn build(&self) -> Result<Types, Error> {
        let opts = MatchOptions {
            require_literal_separator: true, ..MatchOptions::default()
        };
        let selected_globs =
            if self.selected.is_empty() {
                None
            } else {
                let mut bset = glob::SetBuilder::new();
                for name in &self.selected {
                    let globs = match self.types.get(name) {
                        Some(globs) => globs,
                        None => {
                            let msg = name.to_string();
                            return Err(Error::UnrecognizedFileType(msg));
                        }
                    };
                    for glob in globs {
                        try!(bset.add_with(glob, &opts));
                    }
                }
                Some(try!(bset.build_yesno()))
            };
        let negated_globs =
            if self.negated.is_empty() {
                None
            } else {
                let mut bset = glob::SetBuilder::new();
                for name in &self.negated {
                    let globs = match self.types.get(name) {
                        Some(globs) => globs,
                        None => {
                            let msg = name.to_string();
                            return Err(Error::UnrecognizedFileType(msg));
                        }
                    };
                    for glob in globs {
                        try!(bset.add_with(glob, &opts));
                    }
                }
                Some(try!(bset.build_yesno()))
            };
        Ok(Types::new(
            selected_globs, negated_globs, !self.selected.is_empty()))
    }

    /// Return the set of current file type definitions.
    pub fn definitions(&self) -> Vec<FileTypeDef> {
        let mut defs = vec![];
        for (ref name, ref pats) in &self.types {
            let mut pats = pats.to_vec();
            pats.sort();
            defs.push(FileTypeDef {
                name: name.to_string(),
                pats: pats,
            });
        }
        defs.sort_by(|def1, def2| def1.name().cmp(def2.name()));
        defs
    }

    /// Select the file type given by `name`.
    ///
    /// If `name` is `all`, then all file types are selected.
    pub fn select(&mut self, name: &str) -> &mut TypesBuilder {
        if name == "all" {
            for name in self.types.keys() {
                self.selected.push(name.to_string());
            }
        } else {
            self.selected.push(name.to_string());
        }
        self
    }

    /// Ignore the file type given by `name`.
    ///
    /// If `name` is `all`, then all file types are negated.
    pub fn negate(&mut self, name: &str) -> &mut TypesBuilder {
        if name == "all" {
            for name in self.types.keys() {
                self.negated.push(name.to_string());
            }
        } else {
            self.negated.push(name.to_string());
        }
        self
    }

    /// Clear any file type definitions for the type given.
    pub fn clear(&mut self, name: &str) -> &mut TypesBuilder {
        self.types.remove(name);
        self
    }

    /// Add a new file type definition. `name` can be arbitrary and `pat`
    /// should be a glob recognizing file paths belonging to the `name` type.
    pub fn add(&mut self, name: &str, pat: &str) -> &mut TypesBuilder {
        self.types.entry(name.to_string())
            .or_insert(vec![]).push(pat.to_string());
        self
    }

    /// Add a new file type definition specified in string form. The format
    /// is `name:glob`. Names may not include a colon.
    pub fn add_def(&mut self, def: &str) -> Result<(), Error> {
        let name: String = def.chars().take_while(|&c| c != ':').collect();
        let pat: String = def.chars().skip(name.chars().count() + 1).collect();
        if name.is_empty() || pat.is_empty() {
            return Err(Error::InvalidDefinition);
        }
        self.add(&name, &pat);
        Ok(())
    }

    /// Add a set of default file type definitions.
    pub fn add_defaults(&mut self) -> &mut TypesBuilder {
        for &(name, exts) in TYPE_EXTENSIONS {
            for ext in exts {
                self.add(name, ext);
            }
        }
        self
    }
}

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

    macro_rules! matched {
        ($name:ident, $types:expr, $sel:expr, $selnot:expr,
         $path:expr) => {
            matched!($name, $types, $sel, $selnot, $path, true);
        };
        (not, $name:ident, $types:expr, $sel:expr, $selnot:expr,
         $path:expr) => {
            matched!($name, $types, $sel, $selnot, $path, false);
        };
        ($name:ident, $types:expr, $sel:expr, $selnot:expr,
         $path:expr, $matched:expr) => {
            #[test]
            fn $name() {
                let mut btypes = TypesBuilder::new();
                for tydef in $types {
                    btypes.add_def(tydef).unwrap();
                }
                for sel in $sel {
                    btypes.select(sel);
                }
                for selnot in $selnot {
                    btypes.negate(selnot);
                }
                let types = btypes.build().unwrap();
                let mat = types.matched($path, false);
                assert_eq!($matched, !mat.is_ignored());
            }
        };
    }

    fn types() -> Vec<&'static str> {
        vec![
            "html:*.html",
            "html:*.htm",
            "rust:*.rs",
            "js:*.js",
        ]
    }

    matched!(match1, types(), vec!["rust"], vec![], "lib.rs");
    matched!(match2, types(), vec!["html"], vec![], "index.html");
    matched!(match3, types(), vec!["html"], vec![], "index.htm");
    matched!(match4, types(), vec!["html", "rust"], vec![], "main.rs");
    matched!(match5, types(), vec![], vec![], "index.html");
    matched!(match6, types(), vec![], vec!["rust"], "index.html");

    matched!(not, matchnot1, types(), vec!["rust"], vec![], "index.html");
    matched!(not, matchnot2, types(), vec![], vec!["rust"], "main.rs");
}
<commit_msg>Add support for the Swift programming language file type<commit_after>/*!
The types module provides a way of associating glob patterns on file names to
file types.
*/

use std::collections::HashMap;
use std::error::Error as StdError;
use std::fmt;
use std::path::Path;

use regex;

use gitignore::{Match, Pattern};
use glob::{self, MatchOptions};

const TYPE_EXTENSIONS: &'static [(&'static str, &'static [&'static str])] = &[
    ("asm", &["*.asm", "*.s", "*.S"]),
    ("awk", &["*.awk"]),
    ("c", &["*.c", "*.h", "*.H"]),
    ("cbor", &["*.cbor"]),
    ("clojure", &["*.clj", "*.cljs"]),
    ("cmake", &["CMakeLists.txt"]),
    ("coffeescript", &["*.coffee"]),
    ("cpp", &[
        "*.C", "*.cc", "*.cpp", "*.cxx",
        "*.h", "*.H", "*.hh", "*.hpp",
    ]),
    ("csharp", &["*.cs"]),
    ("css", &["*.css"]),
    ("cython", &["*.pyx"]),
    ("dart", &["*.dart"]),
    ("d", &["*.d"]),
    ("elisp", &["*.el"]),
    ("erlang", &["*.erl", "*.hrl"]),
    ("fortran", &[
        "*.f", "*.F", "*.f77", "*.F77", "*.pfo",
        "*.f90", "*.F90", "*.f95", "*.F95",
    ]),
    ("go", &["*.go"]),
    ("groovy", &["*.groovy"]),
    ("haskell", &["*.hs", "*.lhs"]),
    ("html", &["*.htm", "*.html"]),
    ("java", &["*.java"]),
    ("js", &["*.js"]),
    ("json", &["*.json"]),
    ("jsonl", &["*.jsonl"]),
    ("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
    ("lua", &["*.lua"]),
    ("m4", &["*.ac", "*.m4"]),
    ("make", &["gnumakefile", "Gnumakefile", "makefile", "Makefile", "*.mk"]),
    ("markdown", &["*.md"]),
    ("matlab", &["*.m"]),
    ("mk", &["mkfile"]),
    ("ml", &["*.ml"]),
    ("objc", &["*.h", "*.m"]),
    ("objcpp", &["*.h", "*.mm"]),
    ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
    ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm"]),
    ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
    ("py", &["*.py"]),
    ("readme", &["README*", "*README"]),
    ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
    ("rst", &["*.rst"]),
    ("ruby", &["*.rb"]),
    ("rust", &["*.rs"]),
    ("scala", &["*.scala"]),
    ("sh", &["*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh"]),
    ("sql", &["*.sql"]),
    ("swift", &["*.swift"]),
    ("tex", &["*.tex", "*.cls", "*.sty"]),
    ("txt", &["*.txt"]),
    ("toml", &["*.toml", "Cargo.lock"]),
    ("vala", &["*.vala"]),
    ("vb", &["*.vb"]),
    ("vimscript", &["*.vim"]),
    ("xml", &["*.xml"]),
    ("yacc", &["*.y"]),
    ("yaml", &["*.yaml", "*.yml"]),
];

/// Describes all the possible failure conditions for building a file type
/// matcher.
#[derive(Debug)]
pub enum Error {
    /// We tried to select (or negate) a file type that is not defined.
    UnrecognizedFileType(String),
    /// A user specified file type definition could not be parsed.
    InvalidDefinition,
    /// There was an error building the matcher (probably a bad glob).
    Glob(glob::Error),
    /// There was an error compiling a glob as a regex.
    Regex(regex::Error),
}

impl StdError for Error {
    fn description(&self) -> &str {
        match *self {
            Error::UnrecognizedFileType(_) => "unrecognized file type",
            Error::InvalidDefinition => "invalid definition",
            Error::Glob(ref err) => err.description(),
            Error::Regex(ref err) => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::UnrecognizedFileType(ref ty) => {
                write!(f, "unrecognized file type: {}", ty)
            }
            Error::InvalidDefinition => {
                write!(f, "invalid definition (format is type:glob, e.g., \
                           html:*.html)")
            }
            Error::Glob(ref err) => err.fmt(f),
            Error::Regex(ref err) => err.fmt(f),
        }
    }
}

impl From<glob::Error> for Error {
    fn from(err: glob::Error) -> Error {
        Error::Glob(err)
    }
}

impl From<regex::Error> for Error {
    fn from(err: regex::Error) -> Error {
        Error::Regex(err)
    }
}

/// A single file type definition.
#[derive(Clone, Debug)]
pub struct FileTypeDef {
    name: String,
    pats: Vec<String>,
}

impl FileTypeDef {
    /// Return the name of this file type.
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Return the glob patterns used to recognize this file type.
    pub fn patterns(&self) -> &[String] {
        &self.pats
    }
}

/// Types is a file type matcher.
#[derive(Clone, Debug)]
pub struct Types {
    selected: Option<glob::SetYesNo>,
    negated: Option<glob::SetYesNo>,
    has_selected: bool,
    unmatched_pat: Pattern,
}

impl Types {
    /// Creates a new file type matcher from the given Gitignore matcher. If
    /// not Gitignore matcher is provided, then the file type matcher has no
    /// effect.
    ///
    /// If has_selected is true, then at least one file type was selected.
    /// Therefore, any non-matches should be ignored.
    fn new(
        selected: Option<glob::SetYesNo>,
        negated: Option<glob::SetYesNo>,
        has_selected: bool,
    ) -> Types {
        Types {
            selected: selected,
            negated: negated,
            has_selected: has_selected,
            unmatched_pat: Pattern {
                from: Path::new("<filetype>").to_path_buf(),
                original: "<N/A>".to_string(),
                pat: "<N/A>".to_string(),
                whitelist: false,
                only_dir: false,
            },
        }
    }

    /// Creates a new file type matcher that never matches.
    pub fn empty() -> Types {
        Types::new(None, None, false)
    }

    /// Returns a match for the given path against this file type matcher.
    ///
    /// The path is considered whitelisted if it matches a selected file type.
    /// The path is considered ignored if it matched a negated file type.
    /// If at least one file type is selected and path doesn't match, then
    /// the path is also considered ignored.
    pub fn matched<P: AsRef<Path>>(&self, path: P, is_dir: bool) -> Match {
        // If we don't have any matcher, then we can't do anything.
        if self.negated.is_none() && self.selected.is_none() {
            return Match::None;
        }
        // File types don't apply to directories.
        if is_dir {
            return Match::None;
        }
        let path = path.as_ref();
        let name = match path.file_name() {
            Some(name) => name.to_string_lossy(),
            None if self.has_selected => {
                return Match::Ignored(&self.unmatched_pat);
            }
            None => {
                return Match::None;
            }
        };
        if self.negated.as_ref().map(|s| s.is_match(&*name)).unwrap_or(false) {
            return Match::Ignored(&self.unmatched_pat);
        }
        if self.selected.as_ref().map(|s|s.is_match(&*name)).unwrap_or(false) {
            return Match::Whitelist(&self.unmatched_pat);
        }
        if self.has_selected {
            Match::Ignored(&self.unmatched_pat)
        } else {
            Match::None
        }
    }
}

/// TypesBuilder builds a type matcher from a set of file type definitions and
/// a set of file type selections.
pub struct TypesBuilder {
    types: HashMap<String, Vec<String>>,
    selected: Vec<String>,
    negated: Vec<String>,
}

impl TypesBuilder {
    /// Create a new builder for a file type matcher.
    pub fn new() -> TypesBuilder {
        TypesBuilder {
            types: HashMap::new(),
            selected: vec![],
            negated: vec![],
        }
    }

    /// Build the current set of file type definitions *and* selections into
    /// a file type matcher.
    pub fn build(&self) -> Result<Types, Error> {
        let opts = MatchOptions {
            require_literal_separator: true, ..MatchOptions::default()
        };
        let selected_globs =
            if self.selected.is_empty() {
                None
            } else {
                let mut bset = glob::SetBuilder::new();
                for name in &self.selected {
                    let globs = match self.types.get(name) {
                        Some(globs) => globs,
                        None => {
                            let msg = name.to_string();
                            return Err(Error::UnrecognizedFileType(msg));
                        }
                    };
                    for glob in globs {
                        try!(bset.add_with(glob, &opts));
                    }
                }
                Some(try!(bset.build_yesno()))
            };
        let negated_globs =
            if self.negated.is_empty() {
                None
            } else {
                let mut bset = glob::SetBuilder::new();
                for name in &self.negated {
                    let globs = match self.types.get(name) {
                        Some(globs) => globs,
                        None => {
                            let msg = name.to_string();
                            return Err(Error::UnrecognizedFileType(msg));
                        }
                    };
                    for glob in globs {
                        try!(bset.add_with(glob, &opts));
                    }
                }
                Some(try!(bset.build_yesno()))
            };
        Ok(Types::new(
            selected_globs, negated_globs, !self.selected.is_empty()))
    }

    /// Return the set of current file type definitions.
    pub fn definitions(&self) -> Vec<FileTypeDef> {
        let mut defs = vec![];
        for (ref name, ref pats) in &self.types {
            let mut pats = pats.to_vec();
            pats.sort();
            defs.push(FileTypeDef {
                name: name.to_string(),
                pats: pats,
            });
        }
        defs.sort_by(|def1, def2| def1.name().cmp(def2.name()));
        defs
    }

    /// Select the file type given by `name`.
    ///
    /// If `name` is `all`, then all file types are selected.
    pub fn select(&mut self, name: &str) -> &mut TypesBuilder {
        if name == "all" {
            for name in self.types.keys() {
                self.selected.push(name.to_string());
            }
        } else {
            self.selected.push(name.to_string());
        }
        self
    }

    /// Ignore the file type given by `name`.
    ///
    /// If `name` is `all`, then all file types are negated.
    pub fn negate(&mut self, name: &str) -> &mut TypesBuilder {
        if name == "all" {
            for name in self.types.keys() {
                self.negated.push(name.to_string());
            }
        } else {
            self.negated.push(name.to_string());
        }
        self
    }

    /// Clear any file type definitions for the type given.
    pub fn clear(&mut self, name: &str) -> &mut TypesBuilder {
        self.types.remove(name);
        self
    }

    /// Add a new file type definition. `name` can be arbitrary and `pat`
    /// should be a glob recognizing file paths belonging to the `name` type.
    pub fn add(&mut self, name: &str, pat: &str) -> &mut TypesBuilder {
        self.types.entry(name.to_string())
            .or_insert(vec![]).push(pat.to_string());
        self
    }

    /// Add a new file type definition specified in string form. The format
    /// is `name:glob`. Names may not include a colon.
    pub fn add_def(&mut self, def: &str) -> Result<(), Error> {
        let name: String = def.chars().take_while(|&c| c != ':').collect();
        let pat: String = def.chars().skip(name.chars().count() + 1).collect();
        if name.is_empty() || pat.is_empty() {
            return Err(Error::InvalidDefinition);
        }
        self.add(&name, &pat);
        Ok(())
    }

    /// Add a set of default file type definitions.
    pub fn add_defaults(&mut self) -> &mut TypesBuilder {
        for &(name, exts) in TYPE_EXTENSIONS {
            for ext in exts {
                self.add(name, ext);
            }
        }
        self
    }
}

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

    macro_rules! matched {
        ($name:ident, $types:expr, $sel:expr, $selnot:expr,
         $path:expr) => {
            matched!($name, $types, $sel, $selnot, $path, true);
        };
        (not, $name:ident, $types:expr, $sel:expr, $selnot:expr,
         $path:expr) => {
            matched!($name, $types, $sel, $selnot, $path, false);
        };
        ($name:ident, $types:expr, $sel:expr, $selnot:expr,
         $path:expr, $matched:expr) => {
            #[test]
            fn $name() {
                let mut btypes = TypesBuilder::new();
                for tydef in $types {
                    btypes.add_def(tydef).unwrap();
                }
                for sel in $sel {
                    btypes.select(sel);
                }
                for selnot in $selnot {
                    btypes.negate(selnot);
                }
                let types = btypes.build().unwrap();
                let mat = types.matched($path, false);
                assert_eq!($matched, !mat.is_ignored());
            }
        };
    }

    fn types() -> Vec<&'static str> {
        vec![
            "html:*.html",
            "html:*.htm",
            "rust:*.rs",
            "js:*.js",
        ]
    }

    matched!(match1, types(), vec!["rust"], vec![], "lib.rs");
    matched!(match2, types(), vec!["html"], vec![], "index.html");
    matched!(match3, types(), vec!["html"], vec![], "index.htm");
    matched!(match4, types(), vec!["html", "rust"], vec![], "main.rs");
    matched!(match5, types(), vec![], vec![], "index.html");
    matched!(match6, types(), vec![], vec!["rust"], "index.html");

    matched!(not, matchnot1, types(), vec!["rust"], vec![], "index.html");
    matched!(not, matchnot2, types(), vec![], vec!["rust"], "main.rs");
}
<|endoftext|>


<commit_before>// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
//! Traits for loading/saving Registry values
extern crate winapi;
pub use winapi::{HKEY_CLASSES_ROOT,
                 HKEY_CURRENT_USER,
                 HKEY_LOCAL_MACHINE,
                 HKEY_USERS,
                 HKEY_PERFORMANCE_DATA,
                 HKEY_PERFORMANCE_TEXT,
                 HKEY_PERFORMANCE_NLSTEXT,
                 HKEY_CURRENT_CONFIG,
                 HKEY_DYN_DATA,
                 HKEY_CURRENT_USER_LOCAL_SETTINGS};
pub use winapi::{KEY_QUERY_VALUE,
                 KEY_SET_VALUE,
                 KEY_CREATE_SUB_KEY,
                 KEY_ENUMERATE_SUB_KEYS,
                 KEY_NOTIFY,
                 KEY_CREATE_LINK,
                 KEY_WOW64_32KEY,
                 KEY_WOW64_64KEY,
                 KEY_WOW64_RES,
                 KEY_READ,
                 KEY_WRITE,
                 KEY_EXECUTE,
                 KEY_ALL_ACCESS};
pub use winapi::{REG_NONE,
                 REG_SZ,
                 REG_EXPAND_SZ,
                 REG_BINARY,
                 REG_DWORD,
                 REG_DWORD_LITTLE_ENDIAN,
                 REG_DWORD_BIG_ENDIAN,
                 REG_LINK,
                 REG_MULTI_SZ,
                 REG_RESOURCE_LIST,
                 REG_FULL_RESOURCE_DESCRIPTOR,
                 REG_RESOURCE_REQUIREMENTS_LIST,
                 REG_QWORD,
                 REG_QWORD_LITTLE_ENDIAN};
use super::{RegError,RegResult,RegValue};
use super::{to_utf16,v16_to_v8};

/// A trait for types that can be loaded from registry values.
pub trait FromReg {
    fn convert_from_bytes(val: &RegValue) -> RegResult<Self>;
}

impl FromReg for String {
    fn convert_from_bytes(val: &RegValue) -> RegResult<String> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    let pwords = val.bytes.as_ptr() as *mut [u16; 2048 as usize];
                    *pwords
                };
                let mut s:String = String::from_utf16_lossy(&words[..(val.bytes.len()/2)]);
                s.pop(); // remove trailing \0
                if val.vtype == REG_MULTI_SZ {
                    return Ok(s.replace("\u{0}", "\n"))
                }
                Ok(s)
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u32 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u32> {
        match val.vtype {
            REG_DWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u64 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u64> {
        match val.vtype {
            REG_QWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

/// A trait for types that can be written into registry values.
pub trait ToReg {
    fn convert_to_bytes(&self) -> RegValue;
}

impl ToReg for String {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl<'a> ToReg for &'a str {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl ToReg for u32 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u32) as *const u8, 4)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_DWORD
        }
    }
}

impl ToReg for u64 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u64) as *const u8, 8)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_QWORD
        }
    }
}
<commit_msg>Fix: check if string actually ends with \u{0} before trim<commit_after>// Copyright 2015, Igor Shaula
// Licensed under the MIT License <LICENSE or
// http://opensource.org/licenses/MIT>. This file
// may not be copied, modified, or distributed
// except according to those terms.
//! Traits for loading/saving Registry values
extern crate winapi;
pub use winapi::{HKEY_CLASSES_ROOT,
                 HKEY_CURRENT_USER,
                 HKEY_LOCAL_MACHINE,
                 HKEY_USERS,
                 HKEY_PERFORMANCE_DATA,
                 HKEY_PERFORMANCE_TEXT,
                 HKEY_PERFORMANCE_NLSTEXT,
                 HKEY_CURRENT_CONFIG,
                 HKEY_DYN_DATA,
                 HKEY_CURRENT_USER_LOCAL_SETTINGS};
pub use winapi::{KEY_QUERY_VALUE,
                 KEY_SET_VALUE,
                 KEY_CREATE_SUB_KEY,
                 KEY_ENUMERATE_SUB_KEYS,
                 KEY_NOTIFY,
                 KEY_CREATE_LINK,
                 KEY_WOW64_32KEY,
                 KEY_WOW64_64KEY,
                 KEY_WOW64_RES,
                 KEY_READ,
                 KEY_WRITE,
                 KEY_EXECUTE,
                 KEY_ALL_ACCESS};
pub use winapi::{REG_NONE,
                 REG_SZ,
                 REG_EXPAND_SZ,
                 REG_BINARY,
                 REG_DWORD,
                 REG_DWORD_LITTLE_ENDIAN,
                 REG_DWORD_BIG_ENDIAN,
                 REG_LINK,
                 REG_MULTI_SZ,
                 REG_RESOURCE_LIST,
                 REG_FULL_RESOURCE_DESCRIPTOR,
                 REG_RESOURCE_REQUIREMENTS_LIST,
                 REG_QWORD,
                 REG_QWORD_LITTLE_ENDIAN};
use super::{RegError,RegResult,RegValue};
use super::{to_utf16,v16_to_v8};

/// A trait for types that can be loaded from registry values.
pub trait FromReg {
    fn convert_from_bytes(val: &RegValue) -> RegResult<Self>;
}

impl FromReg for String {
    fn convert_from_bytes(val: &RegValue) -> RegResult<String> {
        match val.vtype {
            REG_SZ | REG_EXPAND_SZ | REG_MULTI_SZ => {
                let words = unsafe {
                    let pwords = val.bytes.as_ptr() as *mut [u16; 2048 as usize];
                    *pwords
                };
                let mut s:String = String::from_utf16_lossy(&words[..(val.bytes.len()/2)]);
                while s.ends_with("\u{0}") {s.pop();}
                if val.vtype == REG_MULTI_SZ {
                    return Ok(s.replace("\u{0}", "\n"))
                }
                Ok(s)
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u32 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u32> {
        match val.vtype {
            REG_DWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u32) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

impl FromReg for u64 {
    fn convert_from_bytes(val: &RegValue) -> RegResult<u64> {
        match val.vtype {
            REG_QWORD => {
                Ok(unsafe{ *(val.bytes.as_ptr() as *const u64) })
            },
            _ => Err(RegError{ err: winapi::ERROR_BAD_FILE_TYPE })
        }
    }
}

/// A trait for types that can be written into registry values.
pub trait ToReg {
    fn convert_to_bytes(&self) -> RegValue;
}

impl ToReg for String {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl<'a> ToReg for &'a str {
    fn convert_to_bytes(&self) -> RegValue {
        RegValue{
            bytes: v16_to_v8(&to_utf16(self)),
            vtype: REG_SZ
        }
    }
}

impl ToReg for u32 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u32) as *const u8, 4)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_DWORD
        }
    }
}

impl ToReg for u64 {
    fn convert_to_bytes(&self) -> RegValue {
        let bytes: Vec<u8> = unsafe {
            Vec::from_raw_buf((self as *const u64) as *const u8, 8)
        };
        RegValue{
            bytes: bytes,
            vtype: REG_QWORD
        }
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Concurrent_computing
use std::io::timer::sleep;
use std::rand::random;

fn main() {
    let strings = ~[~"Enjoy", ~"Rosetta", ~"Code"];

    for s in strings.move_iter(){
        do spawn {
            sleep(random::<u8>() as u64);
            println!("{:s}", s);
        }
    }
}<commit_msg>Do removal on concurrent_computing<commit_after>// Implements http://rosettacode.org/wiki/Concurrent_computing
use std::io::timer::sleep;
use std::rand::random;

fn main() {
    let strings = ~[~"Enjoy", ~"Rosetta", ~"Code"];

    for s in strings.move_iter(){
        spawn(proc() {
            sleep(random::<u8>() as u64);
            println!("{:s}", s);
        });
    }
}
<|endoftext|>


<commit_before>use std::sync::atomic;
use std::hash::Hash;
use crossbeam::mem::epoch::{self, Atomic};
use sponge::Sponge;

const ORDERING: atomic::Ordering = atomic::Ordering::Relaxed;

pub struct Pair<K, V> {
    key: K,
    val: V,
}

enum Node<K, V> {
    Leaf(Pair<K, V>),
    Branch(Table<K, V>),
}

#[derive(Default)]
pub struct Table<K, V>  {
    table: [Atomic<Node<K, V>>; 256],
}

impl<K: Hash + Eq, V> Table<K, V> {
    fn two_entries(
        pair_a: Pair<K, V>,
        sponge_a: Sponge,
        pair_b: Pair<K, V>,
        sponge_b: Sponge,
    ) -> Table<K, V> {
        // Start with an empty table.
        let mut table = Table::default();

        // Squeeze the two sponges.
        let pos_a = sponge_a.squeeze();
        let pos_b = sponge_b.squeeze();

        if pos_a != pos_b {
            // The two position did not collide, so we can insert the two pairs at the respective
            // positions
            table[pos_a as usize] = Atomic::new(Some(epoch::Owned::new(Node::Leaf(pair_a))));
            table[pos_b as usize] = Atomic::new(Some(epoch::Owned::new(Node::Leaf(pair_b))));
        } else {
            // The two positions from the sponge matched, so we must place another branch.
            table[pos_a as usize] = Atomic::new(Some(epoch::Owned::new(Node::Branch(
                Table::two_entries(pair_a, sponge_a, pair_b, sponge_b)
            ))));
        }

        table
    }

    pub fn get(&self, key: &K, sponge: Sponge, guard: &epoch::Guard) -> Option<epoch::Shared<V>> {
        // Load the entry and handle the respective cases.
        self.table[sponge.squeeze() as usize].load(guard, ORDERING)
            .and_then(|node| node.map(|node| match node {
            // The entry was a leaf and the keys match, so we can return the entry's value.
            Node::Leaf(Pair { found_key, found_val }) if key == found_key => Some(found_val),
            // The entry is a branch with another table, so we recurse and look up in said
            // sub-table.
            Node::Branch(table) => table.get(key, sponge),
            // The entry is either a leaf but doesn't match, or is a null pointer, meaning there is
            // no entry with the key.
            Node::Leaf(_) => None,
        }))
    }

    pub fn insert(&self, pair: Pair<K, V>, sponge: Sponge) -> Option<V> {
        // We squeeze the sponge to get the right entry of our table, in which we will insert our
        // key-value pair.
        let entry = self.table[sponge.squeeze() as usize];

        // To avoid the ABA problem, this loop is unfortunately necessary, but keep in mind that it
        // will rarely (if ever) run more than one iteration, nor is it mutually exclusive in any
        // way, it just ensures that the entry doesn't change in the meantime in certain specific
        // cases.
        'aba: loop {
            // We use CAS to place the leaf if and only if the entry is empty. Otherwise, we must
            // handle the respective cases.
            return match entry.compare_and_swap(None, Some(epoch::Owned::new(Node::Leaf(pair))), ORDERING) {
                // We successfully set an empty entry to the new key-value pair. This of course
                // implies that the key didn't exist at the time.
                Ok(()) => None,
                // There is a branch table. Insert the key-value pair into it.
                Err(Some(Node::Branch(table))) => table.insert(pair, sponge),
                // The key exists, so we can simply update the value.
                Err(Some(Node::Leaf(found_pair))) if found_pair.key == pair.key
                    // The reason we use CAS here is that the key could have been removed or
                    // updated after we read it initially. If so, we won't update it for the reason
                    // that it was logically inserted (`insert` was called) before it being removed
                    // or updated.  Hence the other version is used, and we don't touch it.
                    => match entry.compare_and_swap(Some(Node::Leaf(found_pair)), Some(Node::Leaf(pair)), ORDERING) {
                        // Everything went well and the leaf was updated.
                        Ok(()) => Some(found_pair.val),
                        // Another node was inserted here, meaning that the table is simply
                        // extended, and the insertion is still potentially valid, so we try to
                        // insert in the inner table.
                        Err(Some(Node::Branch(table))) => table.insert(pair, sponge),
                        // The node was either modified or removed (and maybe replaced by another
                        // node). The insertion was hence invalidated, and we simply pretend we
                        // replaced the leaf we read earlier (even though that was another thread's
                        // work), which we did "logically" (at the point the leaf was read, it had
                        // matching keys).
                        // FIXME: This could be a duplicate.
                        _ => Some(found_pair.val),
                    },
                // Another key exists at the position, so we need to extend the table with a
                // branch, containing both entries.
                Err(Some(Node::Leaf(mut old_pair))) => {
                    // Create a table that contains both the key-value pair we're inserting and the
                    // one on the place, where we want to insert.
                    let new_table = Table::two_entries(pair, sponge, old_pair, {
                        // Generate the sponge of the old pair's key.
                        let mut old_sponge = Sponge::new(&old_pair.key);
                        // Truncate the sponge, so it is at the point, where we are right now, and
                        // the collision is happening.
                        old_sponge.matching(&sponge);

                        old_sponge
                    });
                    // We try to update the current entry to our table. The reason we use CAS is
                    // that we want to ensure that the entry was not changed in the meantime, so we
                    // compare to `old_pair`, which must be a leaf with the old key-value pair, as
                    // the epoch system ensures that it doesn't change while we have the reference
                    // (therefore there is no ABA problem here). So in essence, we check that our
                    // value is still the same as the original, and if it is we update it. If not,
                    // we must handle the new value, which could be anything else (e.g. another
                    // thread could have extended the leaf too because it is inserting the same
                    // pair).
                    match entry.compare_and_swap(old_pair, Some(epoch::Owned::new(Node::Branch(new_table))), ORDERING) {
                        // Our update went smooth, and we have extended the leaf to a branch,
                        // meaning that there now is a sub-table containing the two key-value
                        // pairs.
                        Ok(()) => None,
                        // The update failed. Another thread extended the table, so we will simply
                        // use the table from the new leaf that the other thread created.
                        Err(Some(Node::Branch(table))) => table.insert(pair, sponge),
                        // The node was either updated or removed in the meantime (i.e. before we
                        // logically inserted/`insert` was called), hence we assume this has
                        // affected the logical insertion, which therefore means that it shouldn't
                        // be written as it was overwritten. As a result, we simply return `None`,
                        // marking that no value was replaced.
                        // FIXME: This is wrong. The leaf isn't even of matching key.
                        Err(Some(Node::Leaf(new_pair))) if new_pair.key == pair.key => None,
                        // As something clearly changed between the initial CAS (which attempted to
                        // swap an empty entry) and the most recent CAS, we must re-do the thing in
                        // order to ensure correctness. Otherwise, the insertion might end up lost.
                        _ => continue 'aba,
                    }
                },
                // It is not possible to get `Err(None)` as that was the value we are CAS-ing
                // against.
                Err(None) => unreachable!(),
            };
        }
    }

    pub fn remove(
        &self,
        key: &K,
        sponge: Sponge,
        guard: &epoch::Guard,
    ) -> Option<epoch::Shared<K, V>> {
        // We squeeze the sponge to get the right entry of our table, in which we will potentially
        // remove the key.
        let entry = self.table[sponge.squeeze() as usize];

        // Load the node (if any) and handle its cases.
        entry.load(ORDERING, guard).and_then(|node| node.map(|node| match node {
            // There is a branch, so we must remove the key in the sub-table.
            Node::Branch(table) => table.remove(key, sponge),
            // There was a node with the key, which we will try to remove. We use CAS in order to
            // make sure that it is the same node as the one we read (`entry`), otherwise we might
            // remove a wrong node.
            Node::Leaf(Pair { key: found_key, val }) if found_key == key
                => match entry.compare_and_swap(Some(entry), None, ORDERING) {
                // Removing the node succeeded: It wasn't changed in the meantime.
                Ok(()) => Some(val),
                // The table was extended with a new branch in the meantime, so we will forward the
                // remove call to the respective sub-table.
                Err(Some(Node::Branch(table))) => table.remove(key, sponge),
                // The node was removed or updated by another thread, so our removal is "logically"
                // done, as it was overruled by another thread in the meantime, either by insertion
                // or removal of the same node. We return the value it had at time of the logical
                // removal (i.e. when `remove` was called), as the function acts as if it removed
                // the node.
                // FIXME: This could be a duplicate.
                _ => Some(val),
            },
            // A node with a non-matching key was found. Hence, we have nothing to remove.
            Node::Leaf(..) => None,
        }))
    }

    pub fn for_each<F: Fn(K, V)>(&self, f: F, guard: &epoch::Guard) {
        for i in self.table {
            match i.load(guard, ORDERING) {
                Some(Node::Leaf(Pair { key, val })) => f(key, val),
                Some(Node::Branch(table)) => table.for_each(f, guard),
            }
        }
    }

    pub fn take_each<F: Fn(K, V)>(&self, f: F, guard: &epoch::Guard) {
        for i in self.table {
            match i.load(guard, ORDERING) {
                Some(Node::Leaf(Pair { key, val })) => f(key, val),
                Some(Node::Branch(table)) => table.take_each(f, guard),
            }
        }
    }
}
<commit_msg>Use acq/rel in atomic hashmap to improve performance.<commit_after>use std::sync::atomic;
use std::hash::Hash;
use crossbeam::mem::epoch::{self, Atomic};
use sponge::Sponge;

pub struct Pair<K, V> {
    key: K,
    val: V,
}

enum Node<K, V> {
    Leaf(Pair<K, V>),
    Branch(Table<K, V>),
}

#[derive(Default)]
pub struct Table<K, V>  {
    table: [Atomic<Node<K, V>>; 256],
}

impl<K: Hash + Eq, V> Table<K, V> {
    fn two_entries(
        pair_a: Pair<K, V>,
        sponge_a: Sponge,
        pair_b: Pair<K, V>,
        sponge_b: Sponge,
    ) -> Table<K, V> {
        // Start with an empty table.
        let mut table = Table::default();

        // Squeeze the two sponges.
        let pos_a = sponge_a.squeeze();
        let pos_b = sponge_b.squeeze();

        if pos_a != pos_b {
            // The two position did not collide, so we can insert the two pairs at the respective
            // positions
            table[pos_a as usize] = Atomic::new(Some(epoch::Owned::new(Node::Leaf(pair_a))));
            table[pos_b as usize] = Atomic::new(Some(epoch::Owned::new(Node::Leaf(pair_b))));
        } else {
            // The two positions from the sponge matched, so we must place another branch.
            table[pos_a as usize] = Atomic::new(Some(epoch::Owned::new(Node::Branch(
                Table::two_entries(pair_a, sponge_a, pair_b, sponge_b)
            ))));
        }

        table
    }

    pub fn get(&self, key: &K, sponge: Sponge, guard: &epoch::Guard) -> Option<epoch::Shared<V>> {
        // Load the entry and handle the respective cases.
        self.table[sponge.squeeze() as usize].load(guard, atomic::Ordering::Acquire)
            .and_then(|node| node.map(|node| match node {
            // The entry was a leaf and the keys match, so we can return the entry's value.
            Node::Leaf(Pair { found_key, found_val }) if key == found_key => Some(found_val),
            // The entry is a branch with another table, so we recurse and look up in said
            // sub-table.
            Node::Branch(table) => table.get(key, sponge),
            // The entry is either a leaf but doesn't match, or is a null pointer, meaning there is
            // no entry with the key.
            Node::Leaf(_) => None,
        }))
    }

    pub fn insert(&self, pair: Pair<K, V>, sponge: Sponge) -> Option<V> {
        // We squeeze the sponge to get the right entry of our table, in which we will insert our
        // key-value pair.
        let entry = self.table[sponge.squeeze() as usize];

        // To avoid the ABA problem, this loop is unfortunately necessary, but keep in mind that it
        // will rarely (if ever) run more than one iteration, nor is it mutually exclusive in any
        // way, it just ensures that the entry doesn't change in the meantime in certain specific
        // cases.
        'aba: loop {
            // We use CAS to place the leaf if and only if the entry is empty. Otherwise, we must
            // handle the respective cases.
            return match entry.compare_and_swap(None, Some(epoch::Owned::new(Node::Leaf(pair))), atomic::Ordering::Release) {
                // We successfully set an empty entry to the new key-value pair. This of course
                // implies that the key didn't exist at the time.
                Ok(()) => None,
                // There is a branch table. Insert the key-value pair into it.
                Err(Some(Node::Branch(table))) => table.insert(pair, sponge),
                // The key exists, so we can simply update the value.
                Err(Some(Node::Leaf(found_pair))) if found_pair.key == pair.key
                    // The reason we use CAS here is that the key could have been removed or
                    // updated after we read it initially. If so, we won't update it for the reason
                    // that it was logically inserted (`insert` was called) before it being removed
                    // or updated.  Hence the other version is used, and we don't touch it.
                    => match entry.compare_and_swap(Some(Node::Leaf(found_pair)), Some(Node::Leaf(pair)), atomic::Ordering::Release) {
                        // Everything went well and the leaf was updated.
                        Ok(()) => Some(found_pair.val),
                        // Another node was inserted here, meaning that the table is simply
                        // extended, and the insertion is still potentially valid, so we try to
                        // insert in the inner table.
                        Err(Some(Node::Branch(table))) => table.insert(pair, sponge),
                        // The node was either modified or removed (and maybe replaced by another
                        // node). The insertion was hence invalidated, and we simply pretend we
                        // replaced the leaf we read earlier (even though that was another thread's
                        // work), which we did "logically" (at the point the leaf was read, it had
                        // matching keys).
                        // FIXME: This could be a duplicate.
                        _ => Some(found_pair.val),
                    },
                // Another key exists at the position, so we need to extend the table with a
                // branch, containing both entries.
                Err(Some(Node::Leaf(mut old_pair))) => {
                    // Create a table that contains both the key-value pair we're inserting and the
                    // one on the place, where we want to insert.
                    let new_table = Table::two_entries(pair, sponge, old_pair, {
                        // Generate the sponge of the old pair's key.
                        let mut old_sponge = Sponge::new(&old_pair.key);
                        // Truncate the sponge, so it is at the point, where we are right now, and
                        // the collision is happening.
                        old_sponge.matching(&sponge);

                        old_sponge
                    });
                    // We try to update the current entry to our table. The reason we use CAS is
                    // that we want to ensure that the entry was not changed in the meantime, so we
                    // compare to `old_pair`, which must be a leaf with the old key-value pair, as
                    // the epoch system ensures that it doesn't change while we have the reference
                    // (therefore there is no ABA problem here). So in essence, we check that our
                    // value is still the same as the original, and if it is we update it. If not,
                    // we must handle the new value, which could be anything else (e.g. another
                    // thread could have extended the leaf too because it is inserting the same
                    // pair).
                    match entry.compare_and_swap(old_pair, Some(epoch::Owned::new(Node::Branch(new_table))), atomic::Ordering::Release) {
                        // Our update went smooth, and we have extended the leaf to a branch,
                        // meaning that there now is a sub-table containing the two key-value
                        // pairs.
                        Ok(()) => None,
                        // The update failed. Another thread extended the table, so we will simply
                        // use the table from the new leaf that the other thread created.
                        Err(Some(Node::Branch(table))) => table.insert(pair, sponge),
                        // The node was either updated or removed in the meantime (i.e. before we
                        // logically inserted/`insert` was called), hence we assume this has
                        // affected the logical insertion, which therefore means that it shouldn't
                        // be written as it was overwritten. As a result, we simply return `None`,
                        // marking that no value was replaced.
                        // FIXME: This is wrong. The leaf isn't even of matching key.
                        Err(Some(Node::Leaf(new_pair))) if new_pair.key == pair.key => None,
                        // As something clearly changed between the initial CAS (which attempted to
                        // swap an empty entry) and the most recent CAS, we must re-do the thing in
                        // order to ensure correctness. Otherwise, the insertion might end up lost.
                        _ => continue 'aba,
                    }
                },
                // It is not possible to get `Err(None)` as that was the value we are CAS-ing
                // against.
                Err(None) => unreachable!(),
            };
        }
    }

    pub fn remove(
        &self,
        key: &K,
        sponge: Sponge,
        guard: &epoch::Guard,
    ) -> Option<epoch::Shared<K, V>> {
        // We squeeze the sponge to get the right entry of our table, in which we will potentially
        // remove the key.
        let entry = self.table[sponge.squeeze() as usize];

        // Load the node (if any) and handle its cases.
        entry.load(atomic::Ordering::Acquire, guard).and_then(|node| node.map(|node| match node {
            // There is a branch, so we must remove the key in the sub-table.
            Node::Branch(table) => table.remove(key, sponge),
            // There was a node with the key, which we will try to remove. We use CAS in order to
            // make sure that it is the same node as the one we read (`entry`), otherwise we might
            // remove a wrong node.
            Node::Leaf(Pair { key: found_key, val }) if found_key == key
                => match entry.compare_and_swap(Some(entry), None, atomic::Ordering::Release) {
                // Removing the node succeeded: It wasn't changed in the meantime.
                Ok(()) => Some(val),
                // The table was extended with a new branch in the meantime, so we will forward the
                // remove call to the respective sub-table.
                Err(Some(Node::Branch(table))) => table.remove(key, sponge),
                // The node was removed or updated by another thread, so our removal is "logically"
                // done, as it was overruled by another thread in the meantime, either by insertion
                // or removal of the same node. We return the value it had at time of the logical
                // removal (i.e. when `remove` was called), as the function acts as if it removed
                // the node.
                // FIXME: This could be a duplicate.
                _ => Some(val),
            },
            // A node with a non-matching key was found. Hence, we have nothing to remove.
            Node::Leaf(..) => None,
        }))
    }

    pub fn for_each<F: Fn(K, V)>(&self, f: F, guard: &epoch::Guard) {
        for i in self.table {
            match i.load(guard, atomic::Ordering::Acquire) {
                Some(Node::Leaf(Pair { key, val })) => f(key, val),
                Some(Node::Branch(table)) => table.for_each(f, guard),
            }
        }
    }

    pub fn take_each<F: Fn(K, V)>(&self, f: F, guard: &epoch::Guard) {
        for i in self.table {
            match i.load(guard, atomic::Ordering::Acquire) {
                Some(Node::Leaf(Pair { key, val })) => f(key, val),
                Some(Node::Branch(table)) => table.take_each(f, guard),
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use glib::{Value, Type};
use glib::translate::{
    from_glib_full, from_glib_borrow, from_glib, ToGlibPtr, ToGlibPtrMut, Uninitialized, some_if,
};
use ffi;
use {TreeIter, TreePath};
use libc::c_void;
use glib;

pub struct TreeModel {
    pointer: *mut ffi::GtkTreeModel
}

impl TreeModel {
    pub fn get_flags(&self) -> ::TreeModelFlags {
        unsafe { ffi::gtk_tree_model_get_flags(self.pointer) }
    }

    pub fn get_n_columns(&self) -> i32 {
        unsafe { ffi::gtk_tree_model_get_n_columns(self.pointer) }
    }

    pub fn get_column_type(&self, index_: i32) -> Type {
        unsafe { from_glib(ffi::gtk_tree_model_get_column_type(self.pointer, index_)) }
    }

    pub fn get_iter(&self, path: &TreePath) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_get_iter(self.pointer, iter.to_glib_none_mut().0,
                path.unwrap_pointer());
            some_if(ok, iter)
        }
    }

    pub fn get_iter_from_string(&self, path_string: &str) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_get_iter_from_string(self.pointer,
                iter.to_glib_none_mut().0, path_string.to_glib_none().0);
            some_if(ok, iter)
        }
    }

    pub fn get_iter_first(&self) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_get_iter_first(self.pointer, iter.to_glib_none_mut().0);
            some_if(ok, iter)
        }
     }

    pub fn get_path(&self, iter: &TreeIter) -> Option<TreePath> {
        let tmp_pointer = unsafe {
            ffi::gtk_tree_model_get_path(self.pointer, iter.to_glib_none().0 as *mut _)
        };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(TreePath::wrap_pointer(tmp_pointer))
        }
    }

    pub fn get_value(&self, iter: &TreeIter, column: i32) -> Value {
        unsafe {
            let mut value = Value::new();
            ffi::gtk_tree_model_get_value(self.pointer, iter.to_glib_none().0 as *mut _, column,
                value.as_mut_ptr());
            value
        }
    }

    pub fn iter_next(&self, iter: &mut TreeIter) -> bool {
        unsafe { from_glib(ffi::gtk_tree_model_iter_next(self.pointer, iter.to_glib_none_mut().0)) }
    }

    pub fn iter_previous(&self, iter: &mut TreeIter) -> bool {
        unsafe {
            from_glib(ffi::gtk_tree_model_iter_previous(self.pointer, iter.to_glib_none_mut().0))
        }
    }

    pub fn iter_children(&self, parent: Option<&TreeIter>) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_iter_children(self.pointer, iter.to_glib_none_mut().0,
                parent.to_glib_none().0 as *mut _);
            some_if(ok, iter)
        }
    }

    pub fn iter_has_child(&self, iter: &TreeIter) -> bool {
        unsafe {
            from_glib(ffi::gtk_tree_model_iter_has_child(self.pointer, iter.to_glib_none().0 as *mut _))
        }
    }

    pub fn iter_n_children(&self, iter: Option<&TreeIter>) -> i32 {
        unsafe {
            ffi::gtk_tree_model_iter_n_children(self.pointer, iter.to_glib_none().0 as *mut _)
        }
    }

    pub fn iter_nth_child(&self, parent: Option<&TreeIter>, n: i32) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_iter_nth_child(self.pointer, iter.to_glib_none_mut().0,
                parent.to_glib_none().0 as *mut _, n);
            some_if(ok, iter)
        }
    }

    pub fn iter_parent(&self, child: &TreeIter) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_iter_parent(self.pointer, iter.to_glib_none_mut().0,
                child.to_glib_none().0 as *mut _);
            some_if(ok, iter)
        }
     }

    pub fn get_string_from_iter(&self, iter: &TreeIter) -> Option<String> {
        unsafe {
            from_glib_full(
                ffi::gtk_tree_model_get_string_from_iter(self.pointer,
                                                         iter.to_glib_none().0 as *mut _))
        }
    }

    pub fn row_changed(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_changed(self.pointer, path.unwrap_pointer(), iter.to_glib_none().0 as *mut _) }
    }

    pub fn row_inserted(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_inserted(self.pointer, path.unwrap_pointer(), iter.to_glib_none().0 as *mut _) }
    }

    pub fn row_has_child_toggled(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_has_child_toggled(self.pointer, path.unwrap_pointer(), iter.to_glib_none().0 as *mut _) }
    }

    pub fn row_deleted(&self, path: &TreePath) {
        unsafe { ffi::gtk_tree_model_row_deleted(self.pointer, path.unwrap_pointer()) }
    }

    pub fn foreach<T>(&self, func: fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, user_data: &mut T) {
        let t = &(func, user_data);
        let ca = t as *const (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, &mut T);

        unsafe { ffi::gtk_tree_model_foreach(self.pointer, Some(my_fn), ca as ::glib_ffi::gpointer) }
    }

    #[doc(hidden)]
    pub fn unwrap_pointer(&self) -> *mut ffi::GtkTreeModel {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treemodel: *mut ffi::GtkTreeModel) -> TreeModel {
        TreeModel {
            pointer: c_treemodel
        }
    }
}

unsafe extern "C" fn my_fn(model: *mut ffi::GtkTreeModel, path: *mut ffi::GtkTreePath, iter: *mut ffi::GtkTreeIter, data: *mut c_void) -> ::glib_ffi::gboolean {
    let data: &mut (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: *mut c_void) -> bool, &mut c_void) = mem::transmute(data);
    glib::to_gboolean(data.0(&mut TreeModel::wrap_pointer(model), &mut TreePath::wrap_pointer(path), &mut from_glib_borrow(iter), data.1))
}

impl_drop!(TreeModel, GTK_TREE_MODEL);
<commit_msg>Add a reference when wrapping TreeModel<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::mem;
use glib::{Value, Type};
use glib::translate::{
    from_glib_full, from_glib_borrow, from_glib, ToGlibPtr, ToGlibPtrMut, Uninitialized, some_if,
};
use ffi;
use {TreeIter, TreePath};
use libc::c_void;
use glib;

pub struct TreeModel {
    pointer: *mut ffi::GtkTreeModel
}

impl TreeModel {
    pub fn get_flags(&self) -> ::TreeModelFlags {
        unsafe { ffi::gtk_tree_model_get_flags(self.pointer) }
    }

    pub fn get_n_columns(&self) -> i32 {
        unsafe { ffi::gtk_tree_model_get_n_columns(self.pointer) }
    }

    pub fn get_column_type(&self, index_: i32) -> Type {
        unsafe { from_glib(ffi::gtk_tree_model_get_column_type(self.pointer, index_)) }
    }

    pub fn get_iter(&self, path: &TreePath) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_get_iter(self.pointer, iter.to_glib_none_mut().0,
                path.unwrap_pointer());
            some_if(ok, iter)
        }
    }

    pub fn get_iter_from_string(&self, path_string: &str) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_get_iter_from_string(self.pointer,
                iter.to_glib_none_mut().0, path_string.to_glib_none().0);
            some_if(ok, iter)
        }
    }

    pub fn get_iter_first(&self) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_get_iter_first(self.pointer, iter.to_glib_none_mut().0);
            some_if(ok, iter)
        }
     }

    pub fn get_path(&self, iter: &TreeIter) -> Option<TreePath> {
        let tmp_pointer = unsafe {
            ffi::gtk_tree_model_get_path(self.pointer, iter.to_glib_none().0 as *mut _)
        };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(TreePath::wrap_pointer(tmp_pointer))
        }
    }

    pub fn get_value(&self, iter: &TreeIter, column: i32) -> Value {
        unsafe {
            let mut value = Value::new();
            ffi::gtk_tree_model_get_value(self.pointer, iter.to_glib_none().0 as *mut _, column,
                value.as_mut_ptr());
            value
        }
    }

    pub fn iter_next(&self, iter: &mut TreeIter) -> bool {
        unsafe { from_glib(ffi::gtk_tree_model_iter_next(self.pointer, iter.to_glib_none_mut().0)) }
    }

    pub fn iter_previous(&self, iter: &mut TreeIter) -> bool {
        unsafe {
            from_glib(ffi::gtk_tree_model_iter_previous(self.pointer, iter.to_glib_none_mut().0))
        }
    }

    pub fn iter_children(&self, parent: Option<&TreeIter>) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_iter_children(self.pointer, iter.to_glib_none_mut().0,
                parent.to_glib_none().0 as *mut _);
            some_if(ok, iter)
        }
    }

    pub fn iter_has_child(&self, iter: &TreeIter) -> bool {
        unsafe {
            from_glib(ffi::gtk_tree_model_iter_has_child(self.pointer, iter.to_glib_none().0 as *mut _))
        }
    }

    pub fn iter_n_children(&self, iter: Option<&TreeIter>) -> i32 {
        unsafe {
            ffi::gtk_tree_model_iter_n_children(self.pointer, iter.to_glib_none().0 as *mut _)
        }
    }

    pub fn iter_nth_child(&self, parent: Option<&TreeIter>, n: i32) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_iter_nth_child(self.pointer, iter.to_glib_none_mut().0,
                parent.to_glib_none().0 as *mut _, n);
            some_if(ok, iter)
        }
    }

    pub fn iter_parent(&self, child: &TreeIter) -> Option<TreeIter> {
        unsafe {
            let mut iter = TreeIter::uninitialized();
            let ok = ffi::gtk_tree_model_iter_parent(self.pointer, iter.to_glib_none_mut().0,
                child.to_glib_none().0 as *mut _);
            some_if(ok, iter)
        }
     }

    pub fn get_string_from_iter(&self, iter: &TreeIter) -> Option<String> {
        unsafe {
            from_glib_full(
                ffi::gtk_tree_model_get_string_from_iter(self.pointer,
                                                         iter.to_glib_none().0 as *mut _))
        }
    }

    pub fn row_changed(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_changed(self.pointer, path.unwrap_pointer(), iter.to_glib_none().0 as *mut _) }
    }

    pub fn row_inserted(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_inserted(self.pointer, path.unwrap_pointer(), iter.to_glib_none().0 as *mut _) }
    }

    pub fn row_has_child_toggled(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_has_child_toggled(self.pointer, path.unwrap_pointer(), iter.to_glib_none().0 as *mut _) }
    }

    pub fn row_deleted(&self, path: &TreePath) {
        unsafe { ffi::gtk_tree_model_row_deleted(self.pointer, path.unwrap_pointer()) }
    }

    pub fn foreach<T>(&self, func: fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, user_data: &mut T) {
        let t = &(func, user_data);
        let ca = t as *const (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, &mut T);

        unsafe { ffi::gtk_tree_model_foreach(self.pointer, Some(my_fn), ca as ::glib_ffi::gpointer) }
    }

    #[doc(hidden)]
    pub fn unwrap_pointer(&self) -> *mut ffi::GtkTreeModel {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treemodel: *mut ffi::GtkTreeModel) -> TreeModel {
        unsafe {
            ::gobject_ffi::g_object_ref(c_treemodel as *mut _);
        }
        TreeModel {
            pointer: c_treemodel
        }
    }
}

unsafe extern "C" fn my_fn(model: *mut ffi::GtkTreeModel, path: *mut ffi::GtkTreePath, iter: *mut ffi::GtkTreeIter, data: *mut c_void) -> ::glib_ffi::gboolean {
    let data: &mut (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: *mut c_void) -> bool, &mut c_void) = mem::transmute(data);
    glib::to_gboolean(data.0(&mut TreeModel::wrap_pointer(model), &mut TreePath::wrap_pointer(path), &mut from_glib_borrow(iter), data.1))
}

impl_drop!(TreeModel, GTK_TREE_MODEL);
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#[cfg(not(target_os = "windows"))]
use std::fs;
#[cfg(not(target_os = "windows"))]
use std::path::{Path, PathBuf};
#[cfg(not(target_os = "windows"))]
use std::ffi::OsStr;
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
#[cfg(not(target_os = "windows"))]
use libc::{c_char, lstat, stat, S_IFLNK, S_IFMT};
use Pid;

#[cfg(not(target_os = "windows"))]
pub fn realpath(original: &Path) -> PathBuf {
    if let Some(original_str) = original.to_str() {
        let ori = Path::new(original_str);

        // Right now lstat on windows doesn't work quite well
        if cfg!(windows) {
            return PathBuf::from(ori);
        }
        let result = PathBuf::from(original);
        let mut result_s = result.to_str().unwrap_or("").as_bytes().to_vec();
        result_s.push(0);
        let mut buf: stat = unsafe { ::std::mem::uninitialized() };
        let res = unsafe { lstat(result_s.as_ptr() as *const c_char,
                                 &mut buf as *mut stat) };
        if res < 0 || (buf.st_mode & S_IFMT) != S_IFLNK {
            PathBuf::new()
        } else {
            match fs::read_link(&result) {
                Ok(f) => f,
                Err(_) => PathBuf::new(),
            }
        }
    } else {
        PathBuf::new()
    }
}

/* convert a path to a NUL-terminated Vec<u8> suitable for use with C functions */
#[cfg(not(target_os = "windows"))]
pub fn to_cpath(path: &Path) -> Vec<u8> {
    let path_os: &OsStr = path.as_ref();
    let mut cpath = path_os.as_bytes().to_vec();
    cpath.push(0);
    cpath
}

/// Returns the pid for the current process.
#[cfg(not(target_os = "windows"))]
pub fn get_current_pid() -> Pid {
    unsafe { ::libc::getpid() }
}

/// Returns the pid for the current process.
#[cfg(target_os = "windows")]
pub fn get_current_pid() -> Pid {
    use winapi::um::processthreadsapi::GetCurrentProcessId;

    unsafe { GetCurrentProcessId() as Pid }
}
<commit_msg>Fix android build<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#[cfg(not(target_os = "windows"))]
use std::fs;
#[cfg(not(target_os = "windows"))]
use std::path::{Path, PathBuf};
#[cfg(not(target_os = "windows"))]
use std::ffi::OsStr;
#[cfg(not(target_os = "windows"))]
use std::os::unix::ffi::OsStrExt;
#[cfg(not(target_os = "windows"))]
use libc::{c_char, lstat, stat, S_IFLNK, S_IFMT};
use Pid;

#[cfg(not(target_os = "windows"))]
pub fn realpath(original: &Path) -> PathBuf {
    fn and(x: u32, y: u32) -> u32 {
        x & y
    }

    if let Some(original_str) = original.to_str() {
        let ori = Path::new(original_str);

        // Right now lstat on windows doesn't work quite well
        if cfg!(windows) {
            return PathBuf::from(ori);
        }
        let result = PathBuf::from(original);
        let mut result_s = result.to_str().unwrap_or("").as_bytes().to_vec();
        result_s.push(0);
        let mut buf: stat = unsafe { ::std::mem::uninitialized() };
        let res = unsafe { lstat(result_s.as_ptr() as *const c_char,
                                 &mut buf as *mut stat) };
        if res < 0 || and(buf.st_mode.into(), S_IFMT.into()) != S_IFLNK.into() {
            PathBuf::new()
        } else {
            match fs::read_link(&result) {
                Ok(f) => f,
                Err(_) => PathBuf::new(),
            }
        }
    } else {
        PathBuf::new()
    }
}

/* convert a path to a NUL-terminated Vec<u8> suitable for use with C functions */
#[cfg(not(target_os = "windows"))]
pub fn to_cpath(path: &Path) -> Vec<u8> {
    let path_os: &OsStr = path.as_ref();
    let mut cpath = path_os.as_bytes().to_vec();
    cpath.push(0);
    cpath
}

/// Returns the pid for the current process.
#[cfg(not(target_os = "windows"))]
pub fn get_current_pid() -> Pid {
    unsafe { ::libc::getpid() }
}

/// Returns the pid for the current process.
#[cfg(target_os = "windows")]
pub fn get_current_pid() -> Pid {
    use winapi::um::processthreadsapi::GetCurrentProcessId;

    unsafe { GetCurrentProcessId() as Pid }
}
<|endoftext|>


<commit_before>use std::ops::*;
use std::fmt;
use std::f64::NAN;

use crate::cmd::Command;

#[derive(Clone)]
pub enum Value {
    Num(f64),
    Str(String),
    Variable(String),
    Block(u16, Vec<Command>),
    Null
}

impl Value {
    pub fn as_bool(&self) -> bool {
        match *self {
            Num(n) => !n.is_nan() && n != 0.,
            Str(ref s) => !s.is_empty(),
            Block(_, _) => true,
            // TODO Return error
            Variable(_) => false,
            Null => false
        }
    }
    pub fn make_num(&mut self) {
        let repl = match *self {
            Num(_) => return,
            Null | Block(_, _) => Num(NAN),
            // TODO Return error
            Variable(_) => Num(NAN),
            Str(ref s) => {
                if s == "true" {
                    Num(1.)
                } else if s == "false" {
                    Num(0.)
                } else {
                    Num(s.parse::<f64>().unwrap_or(NAN))
                }
            }
        };
        *self = repl;
    }
    pub fn flatten(self) -> Self {
        match self {
            Block(n, b) => {
                let len = n as usize * b.len();
                let b = b.into_iter().cycle().take(len).collect();

                Block(1, b)
            }
            a => a,
        }
    }
}

impl From<bool> for Value {
    #[inline(always)]
    fn from(b: bool) -> Value {
        if b {
            Num(1.)
        } else {
            Num(0.)
        }
    }
}

impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Null, &Null) => true,
            (&Num(a), &Num(b)) => a == b,
            (&Str(ref a), &Str(ref b)) => a == b,
            _ => false
        }
    }
}

use crate::Value::*;

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Num(ref n) => n.fmt(f),
            Str(ref s) => s.fmt(f),
            Block(_, _) => write!(f, "[code block]"),
            Variable(ref s)=> write!(f, "[variable: {}]", s),
            Null       => "NULL".fmt(f)
        }
    }
}

impl fmt::Debug for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Num(ref n) => n.fmt(f),
            Str(ref s) => s.fmt(f),
            Null => write!(f, "Null"),
            Block(n, ref b) => {
                write!(f, "Block")?;
                let mut dbg = f.debug_set();
                for _ in 0..n {
                    dbg.entries(b);
                }
                dbg.finish()
            },
            Variable(ref s)=> f.debug_tuple("VarName").field(s).finish(),
        }
    }
}

impl Not for Value {
    type Output = Self;
    fn not(self) -> Self {
        self.as_bool().into()
    }
}

impl BitAnd for Value {
    type Output = Self;
    fn bitand(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num((a as i64 & b as i64) as f64),
            (Block(_, _), _) | (_, Block(_, _)) => Null,
            (a, b)  => (a.as_bool() && b.as_bool()).into(),
        }
    }
}

impl BitOr for Value {
    type Output = Self;
    fn bitor(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num((a as i64 | b as i64) as f64),
            (Block(_, _), _) | (_, Block(_, _)) => Null,
            (a, b)  => (a.as_bool() || b.as_bool()).into(),
        }
    }
}

impl Add for Value {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        match (self, other) {
            (Null, b) => b,
            (Str(a), b)  => Str(format!("{}{}", a, b)),
            (a, Null) => a,
            (Num(a), Str(b))  => Str(format!("{}{}", a, b)),
            (Num(a), Num(b)) => Num(a + b),
            (Block(1, mut a), Block(1, b)) => {
                a.extend(b);
                Block(1, a)
            }
            (Block(an, a), Block(bn, b)) => {
                if a == b {
                    Block(an + bn, a)
                } else {
                    let mut res = Vec::with_capacity(an as usize * a.len() + bn as usize * b.len());

                    for _ in 0..an {
                        res.extend(a.iter().cloned())
                    }
                    for _ in 0..bn {
                        res.extend(b.iter().cloned())
                    }
                    Block(1, res)
                }
            }
            _ => Null,
        }
    }
}

impl Mul for Value {
    type Output = Self;
    fn mul(self, other: Self) -> Self {
        match (self, other) {
            (Str(s), Num(n)) | (Num(n), Str(s))  => Str(s.repeat(n as usize)),
            (Num(a), Num(b)) => Num(a * b),
            (Num(n), Block(bn, b)) | (Block(bn, b), Num(n)) => {
                Block(n as u16 * bn, b)
            }
            _ => Null,
        }
    }
}

impl Sub for Value {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num(a - b),
            _ => Null,
        }
    }
}

impl Div for Value {
    type Output = Self;
    fn div(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num(a / b),
            _ => Null,
        }
    }
}

impl Rem for Value {
    type Output = Self;
    fn rem(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num(a % b),
            _ => Null,
        }
    }
}
<commit_msg>Fix not<commit_after>use std::ops::*;
use std::fmt;
use std::f64::NAN;

use crate::cmd::Command;

#[derive(Clone)]
pub enum Value {
    Num(f64),
    Str(String),
    Variable(String),
    Block(u16, Vec<Command>),
    Null
}

impl Value {
    pub fn as_bool(&self) -> bool {
        match *self {
            Num(n) => !n.is_nan() && n != 0.,
            Str(ref s) => !s.is_empty(),
            Block(_, _) => true,
            // TODO Return error
            Variable(_) => false,
            Null => false
        }
    }
    pub fn make_num(&mut self) {
        let repl = match *self {
            Num(_) => return,
            Null | Block(_, _) => Num(NAN),
            // TODO Return error
            Variable(_) => Num(NAN),
            Str(ref s) => {
                if s == "true" {
                    Num(1.)
                } else if s == "false" {
                    Num(0.)
                } else {
                    Num(s.parse::<f64>().unwrap_or(NAN))
                }
            }
        };
        *self = repl;
    }
    pub fn flatten(self) -> Self {
        match self {
            Block(n, b) => {
                let len = n as usize * b.len();
                let b = b.into_iter().cycle().take(len).collect();

                Block(1, b)
            }
            a => a,
        }
    }
}

impl From<bool> for Value {
    #[inline(always)]
    fn from(b: bool) -> Value {
        if b {
            Num(1.)
        } else {
            Num(0.)
        }
    }
}

impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Null, &Null) => true,
            (&Num(a), &Num(b)) => a == b,
            (&Str(ref a), &Str(ref b)) => a == b,
            _ => false
        }
    }
}

use crate::Value::*;

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Num(ref n) => n.fmt(f),
            Str(ref s) => s.fmt(f),
            Block(_, _) => write!(f, "[code block]"),
            Variable(ref s)=> write!(f, "[variable: {}]", s),
            Null       => "NULL".fmt(f)
        }
    }
}

impl fmt::Debug for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Num(ref n) => n.fmt(f),
            Str(ref s) => s.fmt(f),
            Null => write!(f, "Null"),
            Block(n, ref b) => {
                write!(f, "Block")?;
                let mut dbg = f.debug_set();
                for _ in 0..n {
                    dbg.entries(b);
                }
                dbg.finish()
            },
            Variable(ref s)=> f.debug_tuple("VarName").field(s).finish(),
        }
    }
}

impl Not for Value {
    type Output = Self;
    fn not(self) -> Self {
        (!self.as_bool()).into()
    }
}

impl BitAnd for Value {
    type Output = Self;
    fn bitand(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num((a as i64 & b as i64) as f64),
            (Block(_, _), _) | (_, Block(_, _)) => Null,
            (a, b)  => (a.as_bool() && b.as_bool()).into(),
        }
    }
}

impl BitOr for Value {
    type Output = Self;
    fn bitor(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num((a as i64 | b as i64) as f64),
            (Block(_, _), _) | (_, Block(_, _)) => Null,
            (a, b)  => (a.as_bool() || b.as_bool()).into(),
        }
    }
}

impl Add for Value {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        match (self, other) {
            (Null, b) => b,
            (Str(a), b)  => Str(format!("{}{}", a, b)),
            (a, Null) => a,
            (Num(a), Str(b))  => Str(format!("{}{}", a, b)),
            (Num(a), Num(b)) => Num(a + b),
            (Block(1, mut a), Block(1, b)) => {
                a.extend(b);
                Block(1, a)
            }
            (Block(an, a), Block(bn, b)) => {
                if a == b {
                    Block(an + bn, a)
                } else {
                    let mut res = Vec::with_capacity(an as usize * a.len() + bn as usize * b.len());

                    for _ in 0..an {
                        res.extend(a.iter().cloned())
                    }
                    for _ in 0..bn {
                        res.extend(b.iter().cloned())
                    }
                    Block(1, res)
                }
            }
            _ => Null,
        }
    }
}

impl Mul for Value {
    type Output = Self;
    fn mul(self, other: Self) -> Self {
        match (self, other) {
            (Str(s), Num(n)) | (Num(n), Str(s))  => Str(s.repeat(n as usize)),
            (Num(a), Num(b)) => Num(a * b),
            (Num(n), Block(bn, b)) | (Block(bn, b), Num(n)) => {
                Block(n as u16 * bn, b)
            }
            _ => Null,
        }
    }
}

impl Sub for Value {
    type Output = Self;
    fn sub(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num(a - b),
            _ => Null,
        }
    }
}

impl Div for Value {
    type Output = Self;
    fn div(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num(a / b),
            _ => Null,
        }
    }
}

impl Rem for Value {
    type Output = Self;
    fn rem(self, other: Self) -> Self {
        match (self, other) {
            (Num(a), Num(b)) => Num(a % b),
            _ => Null,
        }
    }
}
<|endoftext|>


<commit_before>use std::f64;
use std::iter::{IntoIterator};
use std::cmp::min;

use geom::{Axis};
use geom::ray::Ray;
use geom::shape::{Intersection, Shape};
use geom::shape::bound_box::{BoundBox, Bound};

pub trait BoundedShape: Shape + Bound {}
impl<T: Shape + Bound> BoundedShape for T {}

enum Node<T: BoundedShape> {
    Leaf {shape: T, bound: BoundBox },
    Interior {
        children: [Box<Node<T>>; 2],
        axis: Axis,
        bound: BoundBox,
    }
}

impl<T: BoundedShape> Node<T> {
    fn interior(l: Box<Node<T>>, r: Box<Node<T>>, axis: Axis) -> Node<T> {
        let bound = l.bound().union(&r.bound());
        Node::Interior {
            children: [l, r],
            axis: axis,
            bound: bound
        }
    }

    fn bound(&self) -> BoundBox {
        match self {
            &Node::Leaf {bound, ..} => bound,
            &Node::Interior { bound, ..} => bound
        }
    }

    fn build(shapes: Vec<(T, BoundBox)>) -> Node<T> {
        assert!(shapes.len() > 0);
        if shapes.len() == 1 {
            let (shape, bound) = shapes.into_iter().next().unwrap();
            Node::Leaf {shape: shape, bound: bound }
        } else {
            let (left, right, axis) = Node::partition(shapes);
            Node::interior(
                Box::new(Node::build(left)),
                Box::new(Node::build(right)),
                axis)
        }
    }

    fn partition(mut shapes: Vec<(T, BoundBox)>)
                 -> (Vec<(T, BoundBox)>, Vec<(T, BoundBox)>, Axis) {

        let axis = shapes.iter().map(|&(_, ref bound)| bound.center())
            .collect::<BoundBox>()
            .longext_axis();

        let key = |&(_, ref bound): &(T, BoundBox)| bound.center()[axis];
        shapes.sort_by(|a, b| key(a).partial_cmp(&key(b)).unwrap());
        let mid = shapes.len() / 2;
        let mut l = Vec::new();
        let mut r = Vec::new();
        for (i, item) in shapes.into_iter().enumerate() {
            if i < mid {
                l.push(item);
            } else {
                r.push(item);
            }
        }
        (l, r, axis)
    }
}

pub struct Bvh<T: BoundedShape> {
    root: Node<T>
}

impl<T: BoundedShape> Bvh<T>  {
    pub fn new(triangles: Vec<T>) -> Bvh<T> {
        let with_bounds = triangles.into_iter()
            .map(|t| {
                let bound = t.bound();
                (t, bound)
            }).collect();
        Bvh {
            root: Node::<T>::build(with_bounds)
        }
    }

    pub fn intersect(&self, ray: &Ray) -> Option<Intersection> {
        let mut todo = Vec::with_capacity(64);
        let mut result = None;
        let mut t_bound = f64::INFINITY;

        todo.push(&self.root);
        while let Some(node) = todo.pop() {
            if !node.bound().is_intersected(ray, t_bound) {
                continue;
            }

            match node {
                &Node::Leaf {ref shape, ..} => if let Some(i) = shape.intersect(ray) {
                    let new_result = match result {
                        None => i,
                        Some(j) => min(i, j)
                    };
                    t_bound = t_bound.min(new_result.t);
                    result = Some(new_result);
                },
                &Node::Interior {ref children, axis, ..} => {
                    if ray.direction[axis] < 0.0 {
                        todo.push(&children[0]);
                        todo.push(&children[1]);
                    } else {
                        todo.push(&children[1]);
                        todo.push(&children[0]);
                    }
                }
            }
        }

        result
    }
}
<commit_msg>minor<commit_after>use std::f64;
use std::iter::{IntoIterator};
use std::cmp::min;

use geom::{Axis};
use geom::ray::Ray;
use geom::shape::{Intersection, Shape};
use geom::shape::bound_box::{BoundBox, Bound};

pub trait BoundedShape: Shape + Bound {}
impl<T: Shape + Bound> BoundedShape for T {}

enum Node<T: BoundedShape> {
    Leaf {shape: T, bound: BoundBox },
    Interior {
        children: [Box<Node<T>>; 2],
        axis: Axis,
        bound: BoundBox,
    }
}

impl<T: BoundedShape> Node<T> {
    fn interior(l: Box<Node<T>>, r: Box<Node<T>>, axis: Axis) -> Node<T> {
        let bound = l.bound().union(&r.bound());
        Node::Interior {
            children: [l, r],
            axis: axis,
            bound: bound
        }
    }

    fn bound(&self) -> BoundBox {
        match self {
            &Node::Leaf {bound, ..} => bound,
            &Node::Interior { bound, ..} => bound
        }
    }

    fn build(shapes: Vec<(T, BoundBox)>) -> Node<T> {
        assert!(shapes.len() > 0);
        if shapes.len() == 1 {
            let (shape, bound) = shapes.into_iter().next().unwrap();
            Node::Leaf {shape: shape, bound: bound }
        } else {
            let (left, right, axis) = Node::partition(shapes);
            Node::interior(
                Box::new(Node::build(left)),
                Box::new(Node::build(right)),
                axis)
        }
    }

    fn partition(mut shapes: Vec<(T, BoundBox)>)
                 -> (Vec<(T, BoundBox)>, Vec<(T, BoundBox)>, Axis) {

        let axis = shapes.iter().map(|&(_, ref bound)| bound.center())
            .collect::<BoundBox>()
            .longext_axis();

        let key = |&(_, ref bound): &(T, BoundBox)| bound.center()[axis];
        shapes.sort_by(|a, b| key(a).partial_cmp(&key(b)).unwrap());
        // TODO: use SAH
        let mid = shapes.len() / 2;
        let mut l = Vec::new();
        let mut r = Vec::new();
        for (i, item) in shapes.into_iter().enumerate() {
            if i < mid {
                l.push(item);
            } else {
                r.push(item);
            }
        }
        (l, r, axis)
    }
}

pub struct Bvh<T: BoundedShape> {
    root: Node<T>
}

impl<T: BoundedShape> Bvh<T>  {
    pub fn new(triangles: Vec<T>) -> Bvh<T> {
        let with_bounds = triangles.into_iter()
            .map(|t| {
                let bound = t.bound();
                (t, bound)
            }).collect();
        Bvh {
            root: Node::<T>::build(with_bounds)
        }
    }

    pub fn intersect(&self, ray: &Ray) -> Option<Intersection> {
        let mut todo = Vec::with_capacity(64);
        let mut result = None;
        let mut t_bound = f64::INFINITY;

        todo.push(&self.root);
        while let Some(node) = todo.pop() {
            if !node.bound().is_intersected(ray, t_bound) {
                continue;
            }

            match node {
                &Node::Leaf {ref shape, ..} => if let Some(i) = shape.intersect(ray) {
                    let new_result = match result {
                        None => i,
                        Some(j) => min(i, j)
                    };
                    t_bound = t_bound.min(new_result.t);
                    result = Some(new_result);
                },
                &Node::Interior {ref children, axis, ..} => {
                    if ray.direction[axis] < 0.0 {
                        todo.push(&children[0]);
                        todo.push(&children[1]);
                    } else {
                        todo.push(&children[1]);
                        todo.push(&children[0]);
                    }
                }
            }
        }

        result
    }
}
<|endoftext|>


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

fn main() {
    println!("不存在文件时,创建,然后写数据;如果存在,清空后再写");
    let mut f = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        // .truncate(true)
        .open("foo.txt")
        .ok()
        .expect("Couldn’t open foo.txt");

    println!("{:?}", f);

    let buf = b"whatever just study rust.\n";
    let result = f.write(buf).ok().expect("Write fail.");

    println!("ret: {:?}", result);

    println!("追加内容");
    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .append(true)
        .open("foo.txt")
        .ok()
        .expect("Can NOT append data into file.");
    let buf = b"append some contents.\n";
    let result = f.write(buf).ok().expect("Append contents fail.");
    println!("append op ret: {}", result);
}
<commit_msg>加入详细的文件操作说明.<commit_after>use std::io::Write;

fn main() {
    println!("不存在文件时,创建,然后写数据;如果存在,清空后再写");

    let mut f = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(true) // 不加此行,如果文件存在,不清空原文件,会 seek 到文件件首部
        .open("foo.txt")
        .ok()
        .expect("Couldn’t open foo.txt");
    println!("{:?}", f);

    let buf = b"Whatever just study rust.\n";
    let result = f.write(buf).ok().expect("Write fail.");
    println!("ret: {:?}", result);

    // ---

    println!("追加内容");

    let mut f = std::fs::OpenOptions::new()
        .write(true)
        .append(true)
        .open("foo.txt")
        .ok()
        .expect("Can NOT append data into file.");
    let buf = b"Append some contents.\n";
    let result = f.write(buf)
        .ok()
        .expect("Append contents fail.");
    println!("append op ret: {}", result);
}

<|endoftext|>