<commit_before>extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;

lazy_static! {
    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"declare_clippy_lint!\s*[\{(]\s*pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*(?P<cat>[a-z_]+)\s*,\s*"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]"#).unwrap();
    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"declare_deprecated_lint!\s*[{(]\s*pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]"#).unwrap();
    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
    pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
    pub name: String,
    pub group: String,
    pub desc: String,
    pub deprecation: Option<String>,
    pub module: String,
}

impl Lint {
    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
        Lint {
            name: name.to_lowercase(),
            group: group.to_string(),
            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
            deprecation: deprecation.map(|d| d.to_string()),
            module: module.to_string(),
        }
    }

    pub fn active_lints(lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.deprecation.is_none()).cloned().collect::<Vec<Lint>>()
    }

    pub fn in_lint_group(group: &str, lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.group == group).cloned().collect::<Vec<Lint>>()
    }
}

pub fn collect_all() -> Vec<Lint> {
    let mut lints = vec![];
    for direntry in lint_files() {
        lints.append(&mut collect_from_file(&direntry));
    }
    lints
}

fn collect_from_file(direntry: &fs::DirEntry) -> Vec<Lint> {
    let mut file = fs::File::open(direntry.path()).unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    parse_contents(&content, direntry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> Vec<Lint> {
    let mut lints: Vec<Lint> = DEC_CLIPPY_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename))
        .collect();
    let mut deprecated = DEC_DEPRECATED_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename))
        .collect();
    lints.append(&mut deprecated);
    lints
}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> Vec<fs::DirEntry> {
    let paths = fs::read_dir("../clippy_lints/src").unwrap();
    paths
        .filter_map(|f| f.ok())
        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
        .collect::<Vec<fs::DirEntry>>()
}

#[test]
fn test_parse_contents() {
    let result = parse_contents(
        r#"
declare_clippy_lint! {
    pub PTR_ARG,
    style,
    "really long \
     text"
}

declare_clippy_lint!{
    pub DOC_MARKDOWN,
    pedantic,
    "single line"
}

/// some doc comment
declare_deprecated_lint! {
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}
    "#,
    "module_name");

    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
        Lint::new(
            "should_assert_eq",
            "Deprecated",
            "`assert!()` will be more flexible with RFC 2011",
            Some("`assert!()` will be more flexible with RFC 2011"),
            "module_name"
        ),
    ];
    assert_eq!(expected, result);
}

#[test]
fn test_active_lints() {
    let lints = vec![
        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    let expected = vec![
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    assert_eq!(expected, Lint::active_lints(&lints));
}

#[test]
fn test_in_lint_group() {
    let lints = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
    ];
    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name")
    ];
    assert_eq!(expected, Lint::in_lint_group("style", &lints));
}
<commit_msg>Use insignificant whitespace mode for nice regex<commit_after>extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;
use std::ffi::OsStr;
use std::fs;
use std::io::prelude::*;

lazy_static! {
    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_clippy_lint!\s*[\{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        (?P<cat>[a-z_]+)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"(?x)
        declare_deprecated_lint!\s*[{(]\s*
        pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
    "#).unwrap();
    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
    pub static ref DOCS_LINK: String = "https://rust-lang-nursery.github.io/rust-clippy/master/index.html".to_string();
}

#[derive(Clone, PartialEq, Debug)]
pub struct Lint {
    pub name: String,
    pub group: String,
    pub desc: String,
    pub deprecation: Option<String>,
    pub module: String,
}

impl Lint {
    pub fn new(name: &str, group: &str, desc: &str, deprecation: Option<&str>, module: &str) -> Lint {
        Lint {
            name: name.to_lowercase(),
            group: group.to_string(),
            desc: NL_ESCAPE_RE.replace(&desc.replace("\\\"", "\""), "").to_string(),
            deprecation: deprecation.map(|d| d.to_string()),
            module: module.to_string(),
        }
    }

    pub fn active_lints(lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.deprecation.is_none()).cloned().collect::<Vec<Lint>>()
    }

    pub fn in_lint_group(group: &str, lints: &[Lint]) -> Vec<Lint> {
        lints.iter().filter(|l| l.group == group).cloned().collect::<Vec<Lint>>()
    }
}

pub fn collect_all() -> Vec<Lint> {
    let mut lints = vec![];
    for direntry in lint_files() {
        lints.append(&mut collect_from_file(&direntry));
    }
    lints
}

fn collect_from_file(direntry: &fs::DirEntry) -> Vec<Lint> {
    let mut file = fs::File::open(direntry.path()).unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    parse_contents(&content, direntry.path().file_stem().unwrap().to_str().unwrap())
}

fn parse_contents(content: &str, filename: &str) -> Vec<Lint> {
    let mut lints: Vec<Lint> = DEC_CLIPPY_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename))
        .collect();
    let mut deprecated = DEC_DEPRECATED_LINT_RE
        .captures_iter(&content)
        .map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename))
        .collect();
    lints.append(&mut deprecated);
    lints
}

/// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> Vec<fs::DirEntry> {
    let paths = fs::read_dir("../clippy_lints/src").unwrap();
    paths
        .filter_map(|f| f.ok())
        .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
        .collect::<Vec<fs::DirEntry>>()
}

#[test]
fn test_parse_contents() {
    let result = parse_contents(
        r#"
declare_clippy_lint! {
    pub PTR_ARG,
    style,
    "really long \
     text"
}

declare_clippy_lint!{
    pub DOC_MARKDOWN,
    pedantic,
    "single line"
}

/// some doc comment
declare_deprecated_lint! {
    pub SHOULD_ASSERT_EQ,
    "`assert!()` will be more flexible with RFC 2011"
}
    "#,
    "module_name");

    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
        Lint::new(
            "should_assert_eq",
            "Deprecated",
            "`assert!()` will be more flexible with RFC 2011",
            Some("`assert!()` will be more flexible with RFC 2011"),
            "module_name"
        ),
    ];
    assert_eq!(expected, result);
}

#[test]
fn test_active_lints() {
    let lints = vec![
        Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    let expected = vec![
        Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
    ];
    assert_eq!(expected, Lint::active_lints(&lints));
}

#[test]
fn test_in_lint_group() {
    let lints = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
        Lint::new("doc_markdown", "pedantic", "single line", None, "module_name"),
    ];
    let expected = vec![
        Lint::new("ptr_arg", "style", "really long text", None, "module_name")
    ];
    assert_eq!(expected, Lint::in_lint_group("style", &lints));
}
<|endoftext|>


<commit_before>/// Figure 4.22: Recursively descend a directory hierarchy, counting file types
///
/// takeaways:
///
/// - calling the libc functions was straightforward (with the exception of readdir which
///   is missing in rusts libc (only readdir_r is there)
/// - first forgot to call `closedir` and ran into the "too many files open" limit
/// - the C code in the book suffers is hard to read. Rusts OOP features help a lot in making
///   the code easier to read:
///   + Counter struct instead of static variables and passing a function
///     pointer
///   + Enum instead of constants
///
/// timing wise this rust implementation is about 100% slower than the C program,
/// most probably due to string copying (solved some heavy issues already, but still some
/// are remaining, maybe doing `chdir` into the directory would get rid of that string concat)
///
/// $ rm -rf /tmp/f21
/// $ mkdir /tmp/f21
/// $ touch /tmp/f21/{a,b,c,d,e}
/// $ ln -s /tmp /tmp/f21/tmp
/// $ mkdir /tmp/f21/0
/// $ touch /tmp/f21/0/{f,g,e}
/// $ f22-path-traversal /tmp/f21
///                8 regular files    72.73%
///                2 directories      18.18%
///                1 symbolic links    9.09%
///                0 block special     0.00%
///                0 char special      0.00%
///                0 FIFOs             0.00%
///                0 sockets           0.00%
/// $ rm -rf /tmp/f21

extern crate clap;
extern crate libc;
#[macro_use(print_err)]
extern crate apue;
extern crate errno;

use libc::{stat, S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR,
    S_IFIFO, S_IFLNK, S_IFSOCK, opendir, closedir, lstat};
use apue::{LibcResult};
use apue::my_libc::readdir;
use clap::App;
use std::ffi::{CString, CStr};

struct Counter {
    nreg:u64,
    ndir:u64,
    nblk:u64,
    nchr:u64,
    nfifo:u64,
    nslink:u64,
    nsock:u64,
}

impl Counter {
    fn count_file(&mut self, path: &str, statbuf: &stat) {
        match statbuf.st_mode & S_IFMT {
            S_IFREG => self.nreg += 1,
            S_IFBLK => self.nblk += 1,
            S_IFCHR => self.nchr += 1,
            S_IFIFO => self.nfifo += 1,
            S_IFLNK => self.nslink += 1,
            S_IFSOCK => self.nsock += 1,
            // directories should have type = FTW_D
            S_IFDIR => panic!("found S_IFDIR for {}", path),
            _ => panic!("unknown stat: {}", statbuf.st_mode),
        }
    }
    fn count_other(&mut self, path: &str, typ: FileType) {
        match typ {
            FileType::Directory => self.ndir+= 1,
            FileType::DirectoryCannotRead => print_err!("cannot read dir: {}", path),
            FileType::FileCannotStat => print_err!("cannot stat file: {}", path),
        };
    }
}

impl std::fmt::Debug for Counter {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let total = (self.nsock+self.ndir+self.nslink+self.nfifo+self.nblk+self.nchr+self.nreg) as f32 / 100.0;
        write!(f, r#"        {0:8} regular files    {7:5.2}%
        {1:8} directories      {8:5.2}%
        {2:8} symbolic links   {9:5.2}%
        {3:8} block special    {10:5.2}%
        {4:8} char special     {11:5.2}%
        {5:8} FIFOs            {12:5.2}%
        {6:8} sockets          {13:5.2}%"#,
               self.nreg, self.ndir, self.nslink, self.nblk, self.nchr, self.nfifo, self.nsock,
               self.nreg as f32 / total, self.ndir as f32 / total, self.nslink as f32 / total,
               self.nblk as f32 / total, self.nchr as f32 / total, self.nfifo as f32 / total,
               self.nsock as f32 / total
        )
    }
}

enum FileType {
    Directory,
    DirectoryCannotRead,
    FileCannotStat,
}

unsafe fn myftw(path: &str, cnt: &mut Counter) {
    let p = CString::new(path).unwrap();
    let dp = match opendir(p.as_ptr()).to_option() {
        Some(dp) => dp,
        None => {
            print_err!("cannot open dir: {}", errno::errno());
            cnt.count_other(path, FileType::DirectoryCannotRead);
            return
        },
    };
    while let Some(dirp) = readdir(dp).to_option() {
        let filename = CStr::from_ptr((&(*dirp).d_name).as_ptr()).to_str().expect("invalid string");
        if filename == "." || filename == ".." {
            continue;
        }
        let filename = [path, &filename].join("/");
        let mut statbuf:stat = std::mem::uninitialized();
        if let None = lstat(CString::new(filename.to_owned()).unwrap().as_ptr(), &mut statbuf).to_option() {
            cnt.count_other(&filename, FileType::FileCannotStat);
            continue;
        }
        match statbuf.st_mode & S_IFMT {
            S_IFDIR => {
                cnt.count_other(&filename, FileType::Directory);
                myftw(&filename, cnt);
            },
            _ => cnt.count_file(&filename, &statbuf),
        }
    }
    if let None = closedir(dp).to_option() {
        panic!("can’t close directory {}", path);
    }
}

fn main() {
    unsafe {
        // put ndir=1 because we first start with the initial dir
        let mut c = Counter { nreg: 0, ndir: 1, nblk: 0, nchr: 0, nfifo: 0, nslink: 0, nsock: 0};
        let matches = App::new("tree-traversal")
            .args_from_usage("<path> beginning path for traversal").get_matches();
        let path = matches.value_of("path").unwrap();
        myftw(path, &mut c);
        println!("{:?}", c);
    }
}

<commit_msg>chdir into directories instead of constructing the full path (as suggested in Exercise 4.11)<commit_after>/// Figure 4.22: Recursively descend a directory hierarchy, counting file types
/// adapted to chdir into directories as suggested in Exercise 4.11
///
/// takeaways:
///
/// - calling the libc functions was straightforward (with the exception of readdir which
///   is missing in rusts libc (only readdir_r is there)
/// - first forgot to call `closedir` and ran into the "too many files open" limit
/// - the C code in the book suffers is hard to read. Rusts OOP features help a lot in making
///   the code easier to read:
///   + Counter struct instead of static variables and passing a function
///     pointer
///   + Enum instead of constants
///
/// timing wise this rust implementation is about the same as the c program without chdir.
/// (before implementing chdir it was about 100% slower, most probably due to the fact that
/// this implementation does too much string copying)
///
/// $ rm -rf /tmp/f21
/// $ mkdir /tmp/f21
/// $ touch /tmp/f21/{a,b,c,d,e}
/// $ ln -s /tmp /tmp/f21/tmp
/// $ mkdir /tmp/f21/0
/// $ touch /tmp/f21/0/{f,g,e}
/// $ f22-path-traversal /tmp/f21
///                8 regular files    72.73%
///                2 directories      18.18%
///                1 symbolic links    9.09%
///                0 block special     0.00%
///                0 char special      0.00%
///                0 FIFOs             0.00%
///                0 sockets           0.00%
/// $ rm -rf /tmp/f21

extern crate clap;
extern crate libc;
#[macro_use(print_err, cstr)]
extern crate apue;
extern crate errno;

use libc::{stat, S_IFMT, S_IFDIR, S_IFREG, S_IFBLK, S_IFCHR,
    S_IFIFO, S_IFLNK, S_IFSOCK, opendir, closedir, lstat, chdir};
use apue::{LibcResult};
use apue::my_libc::readdir;
use clap::App;
use std::ffi::{CString, CStr};

struct Counter {
    nreg:u64,
    ndir:u64,
    nblk:u64,
    nchr:u64,
    nfifo:u64,
    nslink:u64,
    nsock:u64,
}

impl Counter {
    fn count_file(&mut self, path: &str, statbuf: &stat) {
        match statbuf.st_mode & S_IFMT {
            S_IFREG => self.nreg += 1,
            S_IFBLK => self.nblk += 1,
            S_IFCHR => self.nchr += 1,
            S_IFIFO => self.nfifo += 1,
            S_IFLNK => self.nslink += 1,
            S_IFSOCK => self.nsock += 1,
            // directories should have type = FTW_D
            S_IFDIR => panic!("found S_IFDIR for {}", path),
            _ => panic!("unknown stat: {}", statbuf.st_mode),
        }
    }
    fn count_other(&mut self, path: &str, typ: FileType) {
        match typ {
            FileType::Directory => self.ndir+= 1,
            FileType::DirectoryCannotRead => print_err!("cannot read dir: {}", path),
            FileType::FileCannotStat => print_err!("cannot stat file: {}", path),
        };
    }
}

impl std::fmt::Debug for Counter {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let total = (self.nsock+self.ndir+self.nslink+self.nfifo+self.nblk+self.nchr+self.nreg) as f32 / 100.0;
        write!(f, r#"        {0:8} regular files    {7:5.2}%
        {1:8} directories      {8:5.2}%
        {2:8} symbolic links   {9:5.2}%
        {3:8} block special    {10:5.2}%
        {4:8} char special     {11:5.2}%
        {5:8} FIFOs            {12:5.2}%
        {6:8} sockets          {13:5.2}%"#,
               self.nreg, self.ndir, self.nslink, self.nblk, self.nchr, self.nfifo, self.nsock,
               self.nreg as f32 / total, self.ndir as f32 / total, self.nslink as f32 / total,
               self.nblk as f32 / total, self.nchr as f32 / total, self.nfifo as f32 / total,
               self.nsock as f32 / total
        )
    }
}

enum FileType {
    Directory,
    DirectoryCannotRead,
    FileCannotStat,
}

unsafe fn myftw(cnt: &mut Counter) {
    let dp = match opendir(cstr!(".")).to_option() {
        Some(dp) => dp,
        None => {
            print_err!("cannot open dir: {}", errno::errno());
            cnt.count_other(".", FileType::DirectoryCannotRead);
            return
        },
    };
    while let Some(dirp) = readdir(dp).to_option() {
        let filename = CStr::from_ptr((&(*dirp).d_name).as_ptr()).to_str().expect("invalid string");
        if filename == "." || filename == ".." {
            continue;
        }
        let mut statbuf:stat = std::mem::uninitialized();
        if let None = lstat(CString::new(filename.to_owned()).unwrap().as_ptr(), &mut statbuf).to_option() {
            cnt.count_other(&filename, FileType::FileCannotStat);
            continue;
        }
        match statbuf.st_mode & S_IFMT {
            S_IFDIR => {
                cnt.count_other(&filename, FileType::Directory);
                if let Some(_) = chdir(cstr!(filename)).to_option() {
                    myftw(cnt);
                    chdir(cstr!(".."));
                }
            },
            _ => cnt.count_file(&filename, &statbuf),
        }
    }
    if let None = closedir(dp).to_option() {
        panic!("can’t close directory {}", errno::errno());
    }
}

fn main() {
    unsafe {
        // put ndir=1 because we first start with the initial dir
        let mut c = Counter { nreg: 0, ndir: 1, nblk: 0, nchr: 0, nfifo: 0, nslink: 0, nsock: 0};
        let matches = App::new("tree-traversal")
            .args_from_usage("<path> beginning path for traversal").get_matches();
        let path = matches.value_of("path").unwrap();
        chdir(cstr!(path));
        myftw(&mut c);
        println!("{:?}", c);
    }
}

<|endoftext|>


<commit_before>extern crate graph_match;

use std::collections::HashMap;
use graph_match::graph::Graph;

pub fn find_verbs(graph: &Graph) -> Option<Vec<usize>> {
    let mut verb_indices: Vec<usize> = Vec::new();
    for node_index in 0..graph.nodes.len() {
        let attrs = try_opt_clone!(graph.nodes[node_index].attributes);
        let pos = try_opt_clone!(attrs.get("pos"));
        if pos.contains("VB") {
            verb_indices.push(node_index);
        }
    }
    return Some(verb_indices);
}

#[test]
fn find_verbs_in_graph() {
    let mut graph = Graph {
        edges: vec![],
        nodes: vec![],
    };
    let mut verb_attrs: HashMap<String, String> = HashMap::new();
    verb_attrs.insert(String::from("pos"), String::from("VBD"));
    let mut other_attrs: HashMap<String, String> = HashMap::new();
    other_attrs.insert(String::from("pos"), String::from("NN"));
    graph.add_node(String::from("node0"), Some(verb_attrs.clone()));
    graph.add_node(String::from("node1"), Some(other_attrs.clone()));
    graph.add_node(String::from("node2"), Some(verb_attrs.clone()));

    assert_eq!(vec![0, 2], find_verbs(&graph).unwrap());
}

pub fn build_queries(verb_indices: &Vec<usize>,
                     graph: &Graph,
                     verbs: &HashMap<String, Vec<String>>,
                     frames: &HashMap<String, (usize, Graph)>,
                     copula_verbs: &Vec<String>)
    -> Option<Vec<(Option<usize>, String)>> {
        let mut queries: Vec<(Option<usize>, String)> = Vec::new();
        for verb_index in verb_indices {
            let attrs = try_opt_clone!(graph.nodes[*verb_index].attributes);
            let lemma = try_opt_clone!(attrs.get("lemma"));
            let raw_patterns = try_opt_clone!(verbs.get(lemma));
            let is_copula = copula_verbs.contains(lemma);
            for pattern in raw_patterns {
                if is_copula {
                    match frames.get(&format!("copula:{}", pattern)) {
                        Some(_) => {
                            queries.push((None, format!("copula:{}", pattern)));
                        },
                        None => println!("Frame missing for: copula:{}", pattern),
                    }
                }
                match frames.get(&format!("{}", pattern)) {
                    Some(_) => {
                        queries.push((Some(*verb_index), pattern.clone()));
                    },
                    None => {
                        if !is_copula {
                            println!("Frame missing for: {}", pattern)
                        }
                    },
                }
            };
            queries.push((Some(*verb_index), String::from("generic:OBJ")));
            queries.push((Some(*verb_index), String::from("generic:XCOMP")));
        }
        return Some(queries);
}

#[test]
fn build_queries_for_verbs_in_graph() {
    use graph_parser;
    let verb_indices = vec![0];
    let mut graph = Graph {
        edges: vec![],
        nodes: vec![],
    };

    let mut verb_attrs: HashMap<String, String> = HashMap::new();
    verb_attrs.insert(String::from("pos"), String::from("VBD"));
    verb_attrs.insert(String::from("lemma"), String::from("run"));

    graph.add_node(String::from("node0"), Some(verb_attrs.clone()));

    let mut verbs: HashMap<String, Vec<String>> = HashMap::new();
    verbs.insert(String::from("run"), vec![String::from("NP V NP")]);
    let mut frames: HashMap<String, (usize, Graph)> = HashMap::new();

    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    let frame = (1, graph_parser::parse(&query_string.to_string()).unwrap());
    frames.insert(String::from("NP V NP"), frame);
    let result = build_queries(&verb_indices, &graph, &verbs, &frames, &vec![]).unwrap();
    assert_eq!(vec![(Some(0), String::from("NP V NP"))], result);
}

pub fn matched_components_to_pattern(matched_components: &graph_match::matching::MatchedComponents,
                                     graph: &Graph)
    -> String {
        let mut pattern: Vec<(usize, String)> = Vec::new();

        for component in &matched_components.list {
            let mut label = String::new();
            match graph.nodes[component.node].attributes {
                Some(ref attrs) => {
                    match attrs.get("lemma") {
                        Some(lemma) => label.push_str(lemma.as_str()),
                        None => label.push_str("BLANK"),
                    }
                }
                None => label.push_str("BLANK"),
            }
            label.push_str(".");
            match component.from_edge {
                Some(edge) => label.push_str(&graph.edges[edge].identifier.as_str()),
                None => label.push_str("root"),
            }
            pattern.push((component.node, label));
        }

        pattern.sort_by(|a, b| a.0.cmp(&b.0));
        return pattern.iter().map(|e| e.1.clone()).collect::<Vec<String>>().join(" ");
    }

#[test]
fn matched_component_pattern() {
    use std::collections::HashMap;
    let mut graph = graph_match::graph::Graph {
        nodes: vec![],
        edges: vec![],
    };
    let mut attributes: HashMap<String, String> = HashMap::new();
    attributes.insert(String::from("lemma"), String::from("cat"));
    graph.add_node(String::from("node1"), Some(attributes.clone()));
    graph.add_edge(0, 0, String::from("edge1"), None);
    let matched_components = graph_match::matching::MatchedComponents {
        list: vec![
            graph_match::matching::Component { from_edge: Some(0), node: 0},
        ],
    };
    assert_eq!(String::from("cat.edge1"),
    matched_components_to_pattern(&matched_components, &graph));
}

pub fn subgraph_nodes_to_extract_string(node_indexes: &Vec<usize>, graph: &Graph) -> String {
    let mut extract_string = String::new();
    let mut sorted_node_indexes = node_indexes.clone();
    sorted_node_indexes.sort_by(|a, b| a.cmp(b));
    for index in sorted_node_indexes {
        match graph.nodes[index].attributes {
            Some(ref attrs) => {
                match attrs.get("before") {
                    Some(value) => extract_string.push_str(&format_context(&value)),
                    _ => {}
                }
                match attrs.get("word") {
                    Some(value) => extract_string.push_str(value.as_str()),
                    _ => {}
                }
                match attrs.get("after") {
                    Some(value) => extract_string.push_str(&format_context(&value)),
                    _ => {}
                }
            }
            None => {}
        };
    }
    return extract_string.replace("  ", " ").replace("COLON", ":");
}

fn format_context(context: &String) -> String {
    let plaintext = match context.as_str() {
        "space" => " ",
        "bigspace" => "\t",
        "newline" => "\n",
        "empty" => "",
        "unknown" => "?",
        _ => "???",
    };
    return String::from(plaintext);
}

#[test]
fn subgraph_string() {
    use std::collections::HashMap;
    let mut graph = graph_match::graph::Graph {
        nodes: vec![],
        edges: vec![],
    };
    let mut attributes: HashMap<String, String> = HashMap::new();
    attributes.insert(String::from("word"), String::from("cat"));
    attributes.insert(String::from("before"), String::from("space"));
    attributes.insert(String::from("after"), String::from("empty"));
    graph.add_node(String::from("node1"), Some(attributes.clone()));
    assert_eq!(String::from(" cat"),
    subgraph_nodes_to_extract_string(&vec![0], &graph));
}
<commit_msg>Move to POS for pattern annotations<commit_after>extern crate graph_match;

use std::collections::HashMap;
use graph_match::graph::Graph;

pub fn find_verbs(graph: &Graph) -> Option<Vec<usize>> {
    let mut verb_indices: Vec<usize> = Vec::new();
    for node_index in 0..graph.nodes.len() {
        let attrs = try_opt_clone!(graph.nodes[node_index].attributes);
        let pos = try_opt_clone!(attrs.get("pos"));
        if pos.contains("VB") {
            verb_indices.push(node_index);
        }
    }
    return Some(verb_indices);
}

#[test]
fn find_verbs_in_graph() {
    let mut graph = Graph {
        edges: vec![],
        nodes: vec![],
    };
    let mut verb_attrs: HashMap<String, String> = HashMap::new();
    verb_attrs.insert(String::from("pos"), String::from("VBD"));
    let mut other_attrs: HashMap<String, String> = HashMap::new();
    other_attrs.insert(String::from("pos"), String::from("NN"));
    graph.add_node(String::from("node0"), Some(verb_attrs.clone()));
    graph.add_node(String::from("node1"), Some(other_attrs.clone()));
    graph.add_node(String::from("node2"), Some(verb_attrs.clone()));

    assert_eq!(vec![0, 2], find_verbs(&graph).unwrap());
}

pub fn build_queries(verb_indices: &Vec<usize>,
                     graph: &Graph,
                     verbs: &HashMap<String, Vec<String>>,
                     frames: &HashMap<String, (usize, Graph)>,
                     copula_verbs: &Vec<String>)
    -> Option<Vec<(Option<usize>, String)>> {
        let mut queries: Vec<(Option<usize>, String)> = Vec::new();
        for verb_index in verb_indices {
            let attrs = try_opt_clone!(graph.nodes[*verb_index].attributes);
            let lemma = try_opt_clone!(attrs.get("lemma"));
            let raw_patterns = try_opt_clone!(verbs.get(lemma));
            let is_copula = copula_verbs.contains(lemma);
            for pattern in raw_patterns {
                if is_copula {
                    match frames.get(&format!("copula:{}", pattern)) {
                        Some(_) => {
                            queries.push((None, format!("copula:{}", pattern)));
                        },
                        None => println!("Frame missing for: copula:{}", pattern),
                    }
                }
                match frames.get(&format!("{}", pattern)) {
                    Some(_) => {
                        queries.push((Some(*verb_index), pattern.clone()));
                    },
                    None => {
                        if !is_copula {
                            println!("Frame missing for: {}", pattern)
                        }
                    },
                }
            };
            queries.push((Some(*verb_index), String::from("generic:OBJ")));
            queries.push((Some(*verb_index), String::from("generic:XCOMP")));
        }
        return Some(queries);
}

#[test]
fn build_queries_for_verbs_in_graph() {
    use graph_parser;
    let verb_indices = vec![0];
    let mut graph = Graph {
        edges: vec![],
        nodes: vec![],
    };

    let mut verb_attrs: HashMap<String, String> = HashMap::new();
    verb_attrs.insert(String::from("pos"), String::from("VBD"));
    verb_attrs.insert(String::from("lemma"), String::from("run"));

    graph.add_node(String::from("node0"), Some(verb_attrs.clone()));

    let mut verbs: HashMap<String, Vec<String>> = HashMap::new();
    verbs.insert(String::from("run"), vec![String::from("NP V NP")]);
    let mut frames: HashMap<String, (usize, Graph)> = HashMap::new();

    let query_string = "type:node identifier:subj\n\
                        type:node identifier:verb pos:VB\n\
                        type:node identifier:obj\n\
                        type:edge identifier:subj source:1 target:0 label:nsubj\n\
                        type:edge identifier:obj source:1 target:2 label:dobj";
    let frame = (1, graph_parser::parse(&query_string.to_string()).unwrap());
    frames.insert(String::from("NP V NP"), frame);
    let result = build_queries(&verb_indices, &graph, &verbs, &frames, &vec![]).unwrap();
    assert_eq!(vec![(Some(0), String::from("NP V NP")), (Some(0), String::from("generic:OBJ")), (Some(0), String::from("generic:XCOMP"))], result);
}

pub fn matched_components_to_pattern(matched_components: &graph_match::matching::MatchedComponents,
                                     graph: &Graph)
    -> String {
        let mut pattern: Vec<(usize, String)> = Vec::new();

        for component in &matched_components.list {
            let mut label = String::new();
            match graph.nodes[component.node].attributes {
                Some(ref attrs) => {
                    match attrs.get("lemma") {
                        Some(lemma) => label.push_str(lemma.as_str()),
                        None => label.push_str("BLANK"),
                    }
                }
                None => label.push_str("BLANK"),
            }
            label.push_str(".");
            match graph.nodes[component.node].attributes {
                Some(ref attrs) => {
                    match attrs.get("pos") {
                        Some(pos) => {
                            if pos.contains("VB") {
                                label.push_str("verb")
                            } else if pos.contains("NN") {
                                label.push_str("noun")
                            } else if pos.contains("PRP") {
                                label.push_str("pn")
                            } else if pos.contains("JJ") {
                                label.push_str("adj")
                            } else if pos.contains("RB") {
                                label.push_str("adv")
                            } else if pos.contains("IN") {
                                label.push_str("prep")
                            } else {
                                label.push_str(pos.as_str())
                            }
                        }
                        None => label.push_str("BLANK")
                    }
                }
                None => label.push_str("BLANK"),
            }
            pattern.push((component.node, label));
        }

        pattern.sort_by(|a, b| a.0.cmp(&b.0));
        return pattern.iter().map(|e| e.1.clone()).collect::<Vec<String>>().join(" ");
    }

#[test]
fn matched_component_pattern() {
    use std::collections::HashMap;
    let mut graph = graph_match::graph::Graph {
        nodes: vec![],
        edges: vec![],
    };
    let mut attributes: HashMap<String, String> = HashMap::new();
    attributes.insert(String::from("lemma"), String::from("cat"));
    attributes.insert(String::from("pos"), String::from("NN"));
    graph.add_node(String::from("node1"), Some(attributes.clone()));
    graph.add_edge(0, 0, String::from("edge1"), None);
    let matched_components = graph_match::matching::MatchedComponents {
        list: vec![
            graph_match::matching::Component { from_edge: Some(0), node: 0},
        ],
    };
    assert_eq!(String::from("cat.noun"),
    matched_components_to_pattern(&matched_components, &graph));
}

pub fn subgraph_nodes_to_extract_string(node_indexes: &Vec<usize>, graph: &Graph) -> String {
    let mut extract_string = String::new();
    let mut sorted_node_indexes = node_indexes.clone();
    sorted_node_indexes.sort_by(|a, b| a.cmp(b));
    for index in sorted_node_indexes {
        match graph.nodes[index].attributes {
            Some(ref attrs) => {
                match attrs.get("before") {
                    Some(value) => extract_string.push_str(&format_context(&value)),
                    _ => {}
                }
                match attrs.get("word") {
                    Some(value) => extract_string.push_str(value.as_str()),
                    _ => {}
                }
                match attrs.get("after") {
                    Some(value) => extract_string.push_str(&format_context(&value)),
                    _ => {}
                }
            }
            None => {}
        };
    }
    return extract_string.replace("  ", " ").replace("COLON", ":");
}

fn format_context(context: &String) -> String {
    let plaintext = match context.as_str() {
        "space" => " ",
        "bigspace" => "\t",
        "newline" => "\n",
        "empty" => "",
        "unknown" => "?",
        _ => "???",
    };
    return String::from(plaintext);
}

#[test]
fn subgraph_string() {
    use std::collections::HashMap;
    let mut graph = graph_match::graph::Graph {
        nodes: vec![],
        edges: vec![],
    };
    let mut attributes: HashMap<String, String> = HashMap::new();
    attributes.insert(String::from("word"), String::from("cat"));
    attributes.insert(String::from("before"), String::from("space"));
    attributes.insert(String::from("after"), String::from("empty"));
    graph.add_node(String::from("node1"), Some(attributes.clone()));
    assert_eq!(String::from(" cat"),
    subgraph_nodes_to_extract_string(&vec![0], &graph));
}
<|endoftext|>


<commit_before>use feeds::Envelope;
use feeds::Message;
use xmlhelper::encode;

#[allow(non_snake_case)]
#[derive(Debug, PartialEq, Serialize)]
pub struct InventoryMessage {
  /// Used to identify an individual product. Each product must have a SKU, and each SKU must
  /// be unique.
  pub SKU: String,

  /// Indicates whether or not an item is available (any positive number = available; 0 = not
  /// available). Every time a quantity is sent for an item, the existing quantity is replaced by the
  /// new quantity in the feed.
  pub Quantity: i32,

  /// The number of days between the order date and the ship date (a whole number between 1
  /// and 30)
  pub FulfillmentLatency: i32,
}

impl Message for InventoryMessage {
  fn get_message_type() -> &'static str {
    "Inventory"
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<InventoryMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      write_xml!(w,
        Messages[][
          [{
            for message in self.messages.iter() {
              let sku: &str = message.data.SKU.as_ref();
              let quantity = message.data.Quantity.to_string();
              let fulfillment_latency = message.data.FulfillmentLatency.to_string();
              write_xml!(w,
                Message[][
                  SKU[][sku]
                  Quantity[][(&quantity)]
                  FulfillmentLatency[][(&fulfillment_latency)]
                ]
              )?;
            }
            Ok(())
          }]
        ]
      )?;
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use feeds::OperationType;
  use xmlhelper::encode::XmlWrite;
  use xmlhelper::encode::{EmitterConfig, EventWriter};

  #[test]
  fn test_inventory_feed() {
    let mut writer =
      EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<InventoryMessage>::new("1234567890".to_owned());
      e.add_message(
        InventoryMessage {
          SKU: "p1".to_owned(),
          Quantity: 100,
          FulfillmentLatency: 0,
        },
        Some(OperationType::PartialUpdate),
      )
      .add_message(
        InventoryMessage {
          SKU: "p2".to_owned(),
          Quantity: 200,
          FulfillmentLatency: 0,
        },
        Some(OperationType::PartialUpdate),
      );
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(
      xml,
      r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>Inventory</MessageType>
  <Messages>
    <Message>
      <SKU>p1</SKU>
      <Quantity>100</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
    <Message>
      <SKU>p2</SKU>
      <Quantity>200</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
  </Messages>
</AmazonEnvelope>"#
    );
  }
}
<commit_msg>refactor: Inventory message id.<commit_after>use feeds::Envelope;
use feeds::Message;
use xmlhelper::encode;

#[allow(non_snake_case)]
#[derive(Debug, PartialEq, Serialize)]
pub struct InventoryMessage {
  pub message_id: String,
  /// Used to identify an individual product. Each product must have a SKU, and each SKU must
  /// be unique.
  pub sku: String,

  /// Indicates whether or not an item is available (any positive number = available; 0 = not
  /// available). Every time a quantity is sent for an item, the existing quantity is replaced by the
  /// new quantity in the feed.
  pub quantity: i32,

  /// The number of days between the order date and the ship date (a whole number between 1
  /// and 30)
  pub fulfillment_latency: i32,
}

impl Message for InventoryMessage {
  fn get_message_type() -> &'static str {
    "Inventory"
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<InventoryMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      write_xml!(w,
        Messages[][
          [{
            for message in self.messages.iter() {
              let sku: &str = message.data.sku.as_ref();
              let quantity = message.data.quantity.to_string();
              let fulfillment_latency = message.data.fulfillment_latency.to_string();
              write_xml!(w,
                Message[][
                  MessageID[][
                    (&message.data.message_id)
                  ]
                  SKU[][sku]
                  Quantity[][(&quantity)]
                  FulfillmentLatency[][(&fulfillment_latency)]
                ]
              )?;
            }
            Ok(())
          }]
        ]
      )?;
      Ok(())
    })
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use feeds::OperationType;
  use xmlhelper::encode::XmlWrite;
  use xmlhelper::encode::{EmitterConfig, EventWriter};

  #[test]
  fn test_inventory_feed() {
    let mut writer =
      EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<InventoryMessage>::new("1234567890".to_owned());
      e.add_message(
        InventoryMessage {
          SKU: "p1".to_owned(),
          Quantity: 100,
          FulfillmentLatency: 0,
        },
        Some(OperationType::PartialUpdate),
      )
      .add_message(
        InventoryMessage {
          SKU: "p2".to_owned(),
          Quantity: 200,
          FulfillmentLatency: 0,
        },
        Some(OperationType::PartialUpdate),
      );
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(
      xml,
      r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>Inventory</MessageType>
  <Messages>
    <Message>
      <SKU>p1</SKU>
      <Quantity>100</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
    <Message>
      <SKU>p2</SKU>
      <Quantity>200</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
  </Messages>
</AmazonEnvelope>"#
    );
  }
}
<|endoftext|>


<commit_before>use libimagstore::store::{Entry, EntryHeader};

use error::{TagError, TagErrorKind};
use result::Result;
use tag::Tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: Vec<Tag>) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: &Tag) -> Result<bool>;
    fn has_tags(&self, ts: &Vec<Tag>) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
                    return Err(TagError::new(TagErrorKind::TagTypeError, None));
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagError::new(TagErrorKind::TagTypeError, None)),
        }
    }

    fn set_tags(&mut self, ts: Vec<Tag>) -> Result<()> {
        let a = ts.iter().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(|e| TagError::new(TagErrorKind::HeaderWriteError, Some(Box::new(e))))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        if tags.is_none() {
            return Ok(());
        }
        let tags = tags.unwrap();

        if !match tags { Value::Array(_) => true, _ => false } {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        match tags {
            Value::Array(tag_array) => {
                let mut new_tags = tag_array.clone();
                new_tags.push(Value::String(t.clone()));

                self.set("imag.tags", Value::Array(new_tags))
                    .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e))))
                    .map(|_| ())
            },

            _ => unreachable!(),
        }
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        if tags.is_none() {
            return Ok(());
        }
        let tags = tags.unwrap();

        if !match tags { Value::Array(_) => true, _ => false } {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        match tags {
            Value::Array(tag_array) => {
                let mut tag_array = tag_array.clone();
                tag_array.retain(|tag| {
                    match tag {
                        &Value::String(ref s) => s.clone() != t,
                        _ => unreachable!(),
                    }
                });

                self.set("imag.tags", Value::Array(tag_array))
                    .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e))))
                    .map(|_| ())
            },

            _ => unreachable!(),
        }
    }

    fn has_tag(&self, t: &Tag) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match tag {
                   &Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &Vec<Tag>) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.err().unwrap());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

<commit_msg>Reimplement add_tag() with get_tags()/set_tags()<commit_after>use libimagstore::store::{Entry, EntryHeader};

use error::{TagError, TagErrorKind};
use result::Result;
use tag::Tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: Vec<Tag>) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: &Tag) -> Result<bool>;
    fn has_tags(&self, ts: &Vec<Tag>) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
                    return Err(TagError::new(TagErrorKind::TagTypeError, None));
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagError::new(TagErrorKind::TagTypeError, None)),
        }
    }

    fn set_tags(&mut self, ts: Vec<Tag>) -> Result<()> {
        let a = ts.iter().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(|e| TagError::new(TagErrorKind::HeaderWriteError, Some(Box::new(e))))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(tags)
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        if tags.is_none() {
            return Ok(());
        }
        let tags = tags.unwrap();

        if !match tags { Value::Array(_) => true, _ => false } {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        match tags {
            Value::Array(tag_array) => {
                let mut tag_array = tag_array.clone();
                tag_array.retain(|tag| {
                    match tag {
                        &Value::String(ref s) => s.clone() != t,
                        _ => unreachable!(),
                    }
                });

                self.set("imag.tags", Value::Array(tag_array))
                    .map_err(|e| TagError::new(TagErrorKind::TagTypeError, Some(Box::new(e))))
                    .map(|_| ())
            },

            _ => unreachable!(),
        }
    }

    fn has_tag(&self, t: &Tag) -> Result<bool> {
        let tags = self.read("imag.tags");
        if tags.is_err() {
            let kind = TagErrorKind::HeaderReadError;
            return Err(TagError::new(kind, Some(Box::new(tags.err().unwrap()))));
        }
        let tags = tags.unwrap();

        if !tags.iter().all(|t| match t { &Value::String(_) => true, _ => false }) {
            return Err(TagError::new(TagErrorKind::TagTypeError, None));
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match tag {
                   &Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &Vec<Tag>) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            let check = self.has_tag(tag);
            if check.is_err() {
                return Err(check.err().unwrap());
            }
            let check = check.unwrap();

            result = result && check;
        }

        Ok(result)
    }

}

<|endoftext|>


<commit_before>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! A collection for storing data associated with a range of values.

use std::cmp::Ordering;
use std::iter::FromIterator;
use std::slice::Iter;

/// The value type for the endpoints of ranges.
pub type Addr = u64;
/// Entries are indexed by a `Range` of `Addr`s.
///
/// The start of the range is inclusive, the end is exclusive.
pub type Range = (Addr, Addr);
/// Entry type, a tuple of `Range` and `T`.
pub type Entry<T> = (Range, T);

/// A `RangeMap` stores values of `T` that map to `Range`s.
pub struct RangeMap<T> {
    /// Entries are stored in a sorted list internally.
    entries: Vec<Entry<T>>,
}

fn compare_address_to_entry<T>(addr : Addr, entry : &Entry<T>) -> Ordering {
    let &((start, end), _) = entry;
    return if start <= addr && end > addr {
        Ordering::Equal
    } else if start > addr {
        Ordering::Greater
    } else {
        Ordering::Less
    }
}

impl<T> RangeMap<T> {
    /// Create a new, empty `RangeMap`.
    pub fn new() -> RangeMap<T> {
        RangeMap::<T> { entries: Vec::new() }
    }

    /// Create a `RangeMap` with `entries`.
    pub fn from(mut entries : Vec<Entry<T>>) -> RangeMap<T> {
        entries.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
        RangeMap::<T> { entries: entries }
    }

    /// Insert `value` in `range`.
    pub fn insert(&mut self, range : Range, value : T) -> Result<(),()> {
        match self.entries.binary_search_by(|&(ref r, ref _v)| r.cmp(&range)) {
            Ok(_) => Err(()),
            Err(index) => {
                self.entries.insert(index, (range, value));
                Ok(())
            }
        }
    }

    /// Find an entry whose `Range` encompasses `addr`.
    pub fn lookup(&self, addr : Addr) -> Option<&T> {
        if let Ok(index) = self.entries.binary_search_by(|ref entry| compare_address_to_entry(addr, entry)) {
            let ((_, _), ref value) = self.entries[index];
            Some(value)
        } else {
            None
        }
    }

    /// Return an iterator over the entries of the `RangeMap`.
    pub fn iter(&self) -> Iter<Entry<T>> {
        self.entries.iter()
    }
}

impl<T> IntoIterator for RangeMap<T> {
    type Item = Entry<T>;
    type IntoIter = <Vec<Entry<T>> as IntoIterator>::IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        self.entries.into_iter()
    }
}

impl<T> FromIterator<Entry<T>> for RangeMap<T> {
    fn from_iter<U>(iterator: U) -> RangeMap<T> where U: IntoIterator<Item=Entry<T>> {
        RangeMap::from(iterator.into_iter().collect())
    }
}

impl<T : Clone> Clone for RangeMap<T> {
    fn clone(&self) -> RangeMap<T> {
        RangeMap::<T> {
            entries: self.entries.clone(),
        }
    }
}

#[test]
fn test_range_map() {
    let mut map = RangeMap::<u32>::new();
    map.insert((7,10), 2).unwrap();
    map.insert((0,4), 1).unwrap();
    map.insert((15,16), 3).unwrap();

    assert_eq!(map.lookup(7).unwrap(), &2);
    assert_eq!(map.lookup(9).unwrap(), &2);
    assert_eq!(map.lookup(0).unwrap(), &1);
    assert_eq!(map.lookup(3).unwrap(), &1);
    assert_eq!(map.lookup(15).unwrap(), &3);
    assert_eq!(map.lookup(4), None);
    assert_eq!(map.lookup(6), None);
    assert_eq!(map.lookup(10), None);
    assert_eq!(map.lookup(16), None);

    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((0,4), 1),
        ((7,10), 2),
        ((15,16), 3),
        ));
}

#[test]
fn test_from_iter() {
    let v = vec!(
        ((10, 20), 1),
        ((5, 6), 2),
        ((20, 22), 3),
        ((8, 10), 4),
        );
    let map = v.into_iter().collect::<RangeMap<u32>>();
    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((5, 6), 2),
        ((8, 10), 4),
        ((10, 20), 1),
        ((20, 22), 3),
        ));
}
<commit_msg>derive PartialEq for RangeMap<commit_after>// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
// file at the top-level directory of this distribution.

//! A collection for storing data associated with a range of values.

use std::cmp::Ordering;
use std::iter::FromIterator;
use std::slice::Iter;

/// The value type for the endpoints of ranges.
pub type Addr = u64;
/// Entries are indexed by a `Range` of `Addr`s.
///
/// The start of the range is inclusive, the end is exclusive.
pub type Range = (Addr, Addr);
/// Entry type, a tuple of `Range` and `T`.
pub type Entry<T> = (Range, T);

/// A `RangeMap` stores values of `T` that map to `Range`s.
#[derive(Debug, PartialEq)]
pub struct RangeMap<T> {
    /// Entries are stored in a sorted list internally.
    entries: Vec<Entry<T>>,
}

fn compare_address_to_entry<T>(addr : Addr, entry : &Entry<T>) -> Ordering {
    let &((start, end), _) = entry;
    return if start <= addr && end > addr {
        Ordering::Equal
    } else if start > addr {
        Ordering::Greater
    } else {
        Ordering::Less
    }
}

impl<T> RangeMap<T> {
    /// Create a new, empty `RangeMap`.
    pub fn new() -> RangeMap<T> {
        RangeMap::<T> { entries: Vec::new() }
    }

    /// Create a `RangeMap` with `entries`.
    pub fn from(mut entries : Vec<Entry<T>>) -> RangeMap<T> {
        entries.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
        RangeMap::<T> { entries: entries }
    }

    /// Insert `value` in `range`.
    pub fn insert(&mut self, range : Range, value : T) -> Result<(),()> {
        match self.entries.binary_search_by(|&(ref r, ref _v)| r.cmp(&range)) {
            Ok(_) => Err(()),
            Err(index) => {
                self.entries.insert(index, (range, value));
                Ok(())
            }
        }
    }

    /// Find an entry whose `Range` encompasses `addr`.
    pub fn lookup(&self, addr : Addr) -> Option<&T> {
        if let Ok(index) = self.entries.binary_search_by(|ref entry| compare_address_to_entry(addr, entry)) {
            let ((_, _), ref value) = self.entries[index];
            Some(value)
        } else {
            None
        }
    }

    /// Return an iterator over the entries of the `RangeMap`.
    pub fn iter(&self) -> Iter<Entry<T>> {
        self.entries.iter()
    }
}

impl<T> IntoIterator for RangeMap<T> {
    type Item = Entry<T>;
    type IntoIter = <Vec<Entry<T>> as IntoIterator>::IntoIter;
    fn into_iter(self) -> Self::IntoIter {
        self.entries.into_iter()
    }
}

impl<T> FromIterator<Entry<T>> for RangeMap<T> {
    fn from_iter<U>(iterator: U) -> RangeMap<T> where U: IntoIterator<Item=Entry<T>> {
        RangeMap::from(iterator.into_iter().collect())
    }
}

impl<T : Clone> Clone for RangeMap<T> {
    fn clone(&self) -> RangeMap<T> {
        RangeMap::<T> {
            entries: self.entries.clone(),
        }
    }
}

#[test]
fn test_range_map() {
    let mut map = RangeMap::<u32>::new();
    map.insert((7,10), 2).unwrap();
    map.insert((0,4), 1).unwrap();
    map.insert((15,16), 3).unwrap();

    assert_eq!(map.lookup(7).unwrap(), &2);
    assert_eq!(map.lookup(9).unwrap(), &2);
    assert_eq!(map.lookup(0).unwrap(), &1);
    assert_eq!(map.lookup(3).unwrap(), &1);
    assert_eq!(map.lookup(15).unwrap(), &3);
    assert_eq!(map.lookup(4), None);
    assert_eq!(map.lookup(6), None);
    assert_eq!(map.lookup(10), None);
    assert_eq!(map.lookup(16), None);

    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((0,4), 1),
        ((7,10), 2),
        ((15,16), 3),
        ));
}

#[test]
fn test_from_iter() {
    let v = vec!(
        ((10, 20), 1),
        ((5, 6), 2),
        ((20, 22), 3),
        ((8, 10), 4),
        );
    let map = v.into_iter().collect::<RangeMap<u32>>();
    let items : Vec<_> = map.into_iter().collect();
    assert_eq!(items, vec!(
        ((5, 6), 2),
        ((8, 10), 4),
        ((10, 20), 1),
        ((20, 22), 3),
        ));
}
<|endoftext|>


<commit_before>use core::ops::{Index, IndexMut};
use core::fmt;

use addr::PhysAddr;
use super::PhysFrame;

use ux::*;
use usize_conversions::usize_from;

#[repr(transparent)]
pub struct PageTableEntry(u64);

impl PageTableEntry {
    pub fn is_unused(&self) -> bool {
        self.0 == 0
    }

    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    pub fn flags(&self) -> PageTableFlags {
        PageTableFlags::from_bits_truncate(self.0)
    }

    pub fn frame(&self) -> Option<PhysFrame> {
        if self.flags().contains(PageTableFlags::PRESENT) {
            let addr = PhysAddr::new(self.0 & 0x000fffff_fffff000);
            Some(PhysFrame::containing_address(addr))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: PhysFrame, flags: PageTableFlags) {
        self.0 = (frame.start_address().as_u64()) | flags.bits();
    }
}

impl fmt::Debug for PageTableEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut f = f.debug_struct("PageTableEntry");
        f.field("frame", &self.frame());
        f.field("flags", &self.flags());
        f.finish()
    }
}

bitflags! {
    pub struct PageTableFlags: u64 {
        const PRESENT =         1 << 0;
        const WRITABLE =        1 << 1;
        const USER_ACCESSIBLE = 1 << 2;
        const WRITE_THROUGH =   1 << 3;
        const NO_CACHE =        1 << 4;
        const ACCESSED =        1 << 5;
        const DIRTY =           1 << 6;
        const HUGE_PAGE =       1 << 7;
        const GLOBAL =          1 << 8;
        const BIT_9 =           1 << 9;
        const BIT_10 =          1 << 10;
        const BIT_11 =          1 << 11;
        const BIT_52 =          1 << 52;
        const BIT_53 =          1 << 53;
        const BIT_54 =          1 << 54;
        const BIT_55 =          1 << 55;
        const BIT_56 =          1 << 56;
        const BIT_57 =          1 << 57;
        const BIT_58 =          1 << 58;
        const BIT_59 =          1 << 59;
        const BIT_60 =          1 << 60;
        const BIT_61 =          1 << 61;
        const BIT_62 =          1 << 62;
        const NO_EXECUTE =      1 << 63;
    }
}

const ENTRY_COUNT: usize = 512;

#[repr(transparent)]
pub struct PageTable {
    entries: [PageTableEntry; ENTRY_COUNT],
}

impl PageTable {
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused();
        }
    }
}

impl Index<usize> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: usize) -> &PageTableEntry {
        &self.entries[index]
    }
}

impl IndexMut<usize> for PageTable {
    fn index_mut(&mut self, index: usize) -> &mut PageTableEntry {
        &mut self.entries[index]
    }
}

impl Index<u9> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: u9) -> &PageTableEntry {
        &self.entries[usize_from(u16::from(index))]
    }
}

impl IndexMut<u9> for PageTable {
    fn index_mut(&mut self, index: u9) -> &mut PageTableEntry {
        &mut self.entries[usize_from(u16::from(index))]
    }
}

impl fmt::Debug for PageTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.entries[..].fmt(f)
    }
}
<commit_msg>Derive Clone for PageTableEntry<commit_after>use core::ops::{Index, IndexMut};
use core::fmt;

use addr::PhysAddr;
use super::PhysFrame;

use ux::*;
use usize_conversions::usize_from;

#[derive(Clone)]
#[repr(transparent)]
pub struct PageTableEntry(u64);

impl PageTableEntry {
    pub fn is_unused(&self) -> bool {
        self.0 == 0
    }

    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    pub fn flags(&self) -> PageTableFlags {
        PageTableFlags::from_bits_truncate(self.0)
    }

    pub fn frame(&self) -> Option<PhysFrame> {
        if self.flags().contains(PageTableFlags::PRESENT) {
            let addr = PhysAddr::new(self.0 & 0x000fffff_fffff000);
            Some(PhysFrame::containing_address(addr))
        } else {
            None
        }
    }

    pub fn set(&mut self, frame: PhysFrame, flags: PageTableFlags) {
        self.0 = (frame.start_address().as_u64()) | flags.bits();
    }
}

impl fmt::Debug for PageTableEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut f = f.debug_struct("PageTableEntry");
        f.field("frame", &self.frame());
        f.field("flags", &self.flags());
        f.finish()
    }
}

bitflags! {
    pub struct PageTableFlags: u64 {
        const PRESENT =         1 << 0;
        const WRITABLE =        1 << 1;
        const USER_ACCESSIBLE = 1 << 2;
        const WRITE_THROUGH =   1 << 3;
        const NO_CACHE =        1 << 4;
        const ACCESSED =        1 << 5;
        const DIRTY =           1 << 6;
        const HUGE_PAGE =       1 << 7;
        const GLOBAL =          1 << 8;
        const BIT_9 =           1 << 9;
        const BIT_10 =          1 << 10;
        const BIT_11 =          1 << 11;
        const BIT_52 =          1 << 52;
        const BIT_53 =          1 << 53;
        const BIT_54 =          1 << 54;
        const BIT_55 =          1 << 55;
        const BIT_56 =          1 << 56;
        const BIT_57 =          1 << 57;
        const BIT_58 =          1 << 58;
        const BIT_59 =          1 << 59;
        const BIT_60 =          1 << 60;
        const BIT_61 =          1 << 61;
        const BIT_62 =          1 << 62;
        const NO_EXECUTE =      1 << 63;
    }
}

const ENTRY_COUNT: usize = 512;

#[repr(transparent)]
pub struct PageTable {
    entries: [PageTableEntry; ENTRY_COUNT],
}

impl PageTable {
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused();
        }
    }
}

impl Index<usize> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: usize) -> &PageTableEntry {
        &self.entries[index]
    }
}

impl IndexMut<usize> for PageTable {
    fn index_mut(&mut self, index: usize) -> &mut PageTableEntry {
        &mut self.entries[index]
    }
}

impl Index<u9> for PageTable {
    type Output = PageTableEntry;

    fn index(&self, index: u9) -> &PageTableEntry {
        &self.entries[usize_from(u16::from(index))]
    }
}

impl IndexMut<u9> for PageTable {
    fn index_mut(&mut self, index: u9) -> &mut PageTableEntry {
        &mut self.entries[usize_from(u16::from(index))]
    }
}

impl fmt::Debug for PageTable {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.entries[..].fmt(f)
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate comm;

use comm::address::Address;
use comm::client;
use comm::client::{Client, Event, Task, TaskSender};
use comm::network::Network;
use comm::node::{Node, UdpNode};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::sync::mpsc;
use std::thread;

#[no_mangle]
pub extern "C" fn comm_initialize() {
    env_logger::init().expect("Couldn't initialize logger");
}

#[no_mangle]
pub extern "C" fn comm_address_for_content(content: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(content) };
    let address = Address::for_content(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_from_str(string: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(string) };
    let address = Address::from_str(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_null() -> *const Address {
    Box::into_raw(Box::new(Address::null()))
}

#[no_mangle]
pub extern "C" fn comm_address_copy(address: *const Address) -> *const Address {
    let copy = unsafe { *address }.clone();
    Box::into_raw(Box::new(copy))
}

#[no_mangle]
pub extern "C" fn comm_address_to_str(address: *const Address) -> *const c_char {
    let string = unsafe { *address }.to_str();
    CString::new(string).unwrap().as_ptr()
}

#[no_mangle]
pub unsafe extern "C" fn comm_address_destroy(address: *mut Address) {
    let _ = Box::from_raw(address);
}

#[no_mangle]
pub extern "C" fn comm_udp_node_new(
    address: *const Address, socket_address: *const c_char) -> *const UdpNode {
    let socket_address: &CStr = unsafe { CStr::from_ptr(socket_address) };
    let node = UdpNode::new(unsafe { *address }, socket_address.to_str().unwrap());
    Box::into_raw(Box::new(node))
}

#[no_mangle]
pub unsafe extern "C" fn comm_udp_node_destroy(udp_node: *mut UdpNode) {
    let _ = Box::from_raw(udp_node);
}

#[no_mangle]
pub extern "C" fn comm_network_new(
    self_address: *mut Address, host: *const c_char, routers: *mut *mut UdpNode, routers_count: usize) -> *mut Network {
    let self_address = unsafe { *self_address };
    let host: &CStr = unsafe { CStr::from_ptr(host) };
    let routers = unsafe { Vec::from_raw_parts(routers, routers_count, routers_count) };
    let routers: Vec<Box<Node>> = routers.into_iter().map(|r| unsafe {
        Box::from_raw(r) as Box<Node>
    }).collect();
    let network = Network::new(self_address, host.to_str().unwrap(), routers);
    Box::into_raw(Box::new(network))
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_run(network: *mut Network) {
    let network = Box::from_raw(network);
    network.run();
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_destroy(network: *mut Network) {
    let _ = Box::from_raw(network);
}

#[no_mangle]
pub extern "C" fn comm_text_message_new(sender: *mut Address, text: *const c_char) -> *const client::messages::TextMessage {
    let sender = unsafe { *Box::from_raw(sender) };
    let c_str: &CStr = unsafe { CStr::from_ptr(text) };
    let message_text = c_str.to_str().unwrap().to_string();

    Box::into_raw(Box::new(client::messages::TextMessage::new(sender, message_text)))
}

#[no_mangle]
pub extern "C" fn comm_text_message_text(text_message: *const client::messages::TextMessage) -> *const c_char {
    let text_message = unsafe { &*text_message };
    CString::new(text_message.text.clone()).unwrap().as_ptr()
}

#[no_mangle]
pub extern "C" fn comm_text_message_sender(text_message: *const client::messages::TextMessage) -> *const Address {
    let text_message = unsafe { &*text_message };
    Box::into_raw(Box::new(text_message.sender))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_new(address: *const Address) -> *mut Client {
    Box::into_raw(Box::new(Client::new(*address)))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_run(
    client: *mut Client, network: *mut Network) -> *mut TaskSender {
    let client = Box::from_raw(client);
    let network = *Box::from_raw(network);
    Box::into_raw(Box::new(client.run(network)))
}

#[no_mangle]
pub extern "C" fn comm_client_register_text_message_received_callback(
    client: *mut Client, callback: extern fn(*const client::messages::TextMessage) -> ()) {

    let client = unsafe { &mut *client };
    let (event_sender, events) = mpsc::channel();
    client.register_event_listener(event_sender);

    thread::spawn(move || {
        for event in events {
            if let Event::ReceivedTextMessage(text_message) = event {
                callback(Box::into_raw(Box::new(text_message)));
            }
        }
    });
}

#[no_mangle]
pub extern "C" fn comm_client_commands_send_text_message(
    commands: *mut TaskSender,
    recipient: *mut Address,
    text_message: *mut client::messages::TextMessage) {
    let commands = unsafe { &mut *commands };
    let recipient = unsafe { *Box::from_raw(recipient) };
    let text_message = unsafe { *Box::from_raw(text_message) };
    commands.send(Task::ScheduleMessageDelivery(recipient, text_message)).unwrap();
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_destroy(client: *mut Client) {
    let _ = Box::from_raw(client);
}
<commit_msg>Leak the strings return by Rust funcs<commit_after>extern crate env_logger;
extern crate comm;

use comm::address::Address;
use comm::client;
use comm::client::{Client, Event, Task, TaskSender};
use comm::network::Network;
use comm::node::{Node, UdpNode};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::sync::mpsc;
use std::thread;

#[no_mangle]
pub extern "C" fn comm_initialize() {
    env_logger::init().expect("Couldn't initialize logger");
}

#[no_mangle]
pub extern "C" fn comm_address_for_content(content: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(content) };
    let address = Address::for_content(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_from_str(string: *const c_char) -> *const Address {
    let c_str: &CStr = unsafe { CStr::from_ptr(string) };
    let address = Address::from_str(c_str.to_str().unwrap());
    Box::into_raw(Box::new(address))
}

#[no_mangle]
pub extern "C" fn comm_address_null() -> *const Address {
    Box::into_raw(Box::new(Address::null()))
}

#[no_mangle]
pub extern "C" fn comm_address_copy(address: *const Address) -> *const Address {
    let copy = unsafe { *address }.clone();
    Box::into_raw(Box::new(copy))
}

#[no_mangle]
pub extern "C" fn comm_address_to_str(address: *const Address) -> *const c_char {
    let string = unsafe { *address }.to_str();
    let string = CString::new(string).unwrap();
    let pointer = string.as_ptr();
    std::mem::forget(string);
    pointer
}

#[no_mangle]
pub unsafe extern "C" fn comm_address_destroy(address: *mut Address) {
    let _ = Box::from_raw(address);
}

#[no_mangle]
pub extern "C" fn comm_udp_node_new(
    address: *const Address, socket_address: *const c_char) -> *const UdpNode {
    let socket_address: &CStr = unsafe { CStr::from_ptr(socket_address) };
    let node = UdpNode::new(unsafe { *address }, socket_address.to_str().unwrap());
    Box::into_raw(Box::new(node))
}

#[no_mangle]
pub unsafe extern "C" fn comm_udp_node_destroy(udp_node: *mut UdpNode) {
    let _ = Box::from_raw(udp_node);
}

#[no_mangle]
pub extern "C" fn comm_network_new(
    self_address: *mut Address, host: *const c_char, routers: *mut *mut UdpNode, routers_count: usize) -> *mut Network {
    let self_address = unsafe { *self_address };
    let host: &CStr = unsafe { CStr::from_ptr(host) };
    let routers = unsafe { Vec::from_raw_parts(routers, routers_count, routers_count) };
    let routers: Vec<Box<Node>> = routers.into_iter().map(|r| unsafe {
        Box::from_raw(r) as Box<Node>
    }).collect();
    let network = Network::new(self_address, host.to_str().unwrap(), routers);
    Box::into_raw(Box::new(network))
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_run(network: *mut Network) {
    let network = Box::from_raw(network);
    network.run();
}

#[no_mangle]
pub unsafe extern "C" fn comm_network_destroy(network: *mut Network) {
    let _ = Box::from_raw(network);
}

#[no_mangle]
pub extern "C" fn comm_text_message_new(sender: *mut Address, text: *const c_char) -> *const client::messages::TextMessage {
    let sender = unsafe { *Box::from_raw(sender) };
    let c_str: &CStr = unsafe { CStr::from_ptr(text) };
    let message_text = c_str.to_str().unwrap().to_string();

    Box::into_raw(Box::new(client::messages::TextMessage::new(sender, message_text)))
}

#[no_mangle]
pub extern "C" fn comm_text_message_text(text_message: *const client::messages::TextMessage) -> *const c_char {
    let text_message = unsafe { &*text_message };
    let string = CString::new(text_message.text.clone()).unwrap();
    let pointer = string.as_ptr();
    std::mem::forget(string);
    pointer
}

#[no_mangle]
pub extern "C" fn comm_text_message_sender(text_message: *const client::messages::TextMessage) -> *const Address {
    let text_message = unsafe { &*text_message };
    Box::into_raw(Box::new(text_message.sender))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_new(address: *const Address) -> *mut Client {
    Box::into_raw(Box::new(Client::new(*address)))
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_run(
    client: *mut Client, network: *mut Network) -> *mut TaskSender {
    let client = Box::from_raw(client);
    let network = *Box::from_raw(network);
    Box::into_raw(Box::new(client.run(network)))
}

#[no_mangle]
pub extern "C" fn comm_client_register_text_message_received_callback(
    client: *mut Client, callback: extern fn(*const client::messages::TextMessage) -> ()) {

    let client = unsafe { &mut *client };
    let (event_sender, events) = mpsc::channel();
    client.register_event_listener(event_sender);

    thread::spawn(move || {
        for event in events {
            if let Event::ReceivedTextMessage(text_message) = event {
                callback(Box::into_raw(Box::new(text_message)));
            }
        }
    });
}

#[no_mangle]
pub extern "C" fn comm_client_commands_send_text_message(
    commands: *mut TaskSender,
    recipient: *mut Address,
    text_message: *mut client::messages::TextMessage) {
    let commands = unsafe { &mut *commands };
    let recipient = unsafe { *Box::from_raw(recipient) };
    let text_message = unsafe { *Box::from_raw(text_message) };
    commands.send(Task::ScheduleMessageDelivery(recipient, text_message)).unwrap();
}

#[no_mangle]
pub unsafe extern "C" fn comm_client_destroy(client: *mut Client) {
    let _ = Box::from_raw(client);
}
<|endoftext|>


<commit_before>
//! Storing sounds, textures, animations etc.

// Extern crates.
use std::os::self_exe_path;

/// A place to store sounds, textures, animations etc.
///
/// The idea is to have one object which the app can use
/// to load assets for the game with a simple interface.
pub struct AssetStore {
    // The folder to load assets from.
    assets_folder: Option<String>,
}

impl AssetStore {
    /// Creates a new `AssetStore` from an assets folder.
    pub fn from_folder(assets_folder: &str) -> AssetStore {
        AssetStore {
            assets_folder: Some(assets_folder.to_string()),
        }
    }

    /// Creates an empty `AssetStore` with no assets.
    pub fn empty() -> AssetStore {
        AssetStore {
            assets_folder: None,
        }
    }

    /// Returns the path of an asset file.
    pub fn path(&self, file: &str) -> Result<Path, String> {
        let folder = self.assets_folder.as_ref().unwrap();
        let exe_path = self_exe_path();
        let exe_path = match exe_path {
            Some(path) => path,
            None => return Err("Could not get the path to executable".to_string()),
        };
        Ok(exe_path.join(Path::new(folder.as_slice())).join(Path::new(file)))
    }
}

<commit_msg>Make `AssetStore` return Err when empty<commit_after>
//! Storing sounds, textures, animations etc.

// Extern crates.
use std::os::self_exe_path;

/// A place to store sounds, textures, animations etc.
///
/// The idea is to have one object which the app can use
/// to load assets for the game with a simple interface.
pub struct AssetStore {
    // The folder to load assets from.
    assets_folder: Option<String>,
}

impl AssetStore {
    /// Creates a new `AssetStore` from an assets folder.
    pub fn from_folder(assets_folder: &str) -> AssetStore {
        AssetStore {
            assets_folder: Some(assets_folder.to_string()),
        }
    }

    /// Creates an empty `AssetStore` with no assets.
    pub fn empty() -> AssetStore {
        AssetStore {
            assets_folder: None,
        }
    }

    /// Returns the path of an asset file.
    pub fn path(&self, file: &str) -> Result<Path, String> {
        let folder = match self.assets_folder.as_ref() {
            Some(folder) => folder,
            None => return Err(
                    "The assets folder is not set".to_string()
                )
        };
        let exe_path = self_exe_path();
        let exe_path = match exe_path {
            Some(path) => path,
            None => return Err(
                    "Could not get the path to executable".to_string()
                ),
        };
        Ok(exe_path.join(Path::new(folder.as_slice())).join(Path::new(file)))
    }
}

<|endoftext|>