<commit_before>extern crate chrono;
extern crate walkdir;

use self::chrono::{Duration, UTC};
use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};

use std::borrow::Borrow;
use std::collections::{BTreeSet, VecDeque};
use std::fs::{self, DirEntry};
use std::io::Error as IoError;
use std::os::unix::fs::MetadataExt;
use std::path::{MAIN_SEPARATOR, Path, PathBuf};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),+) => ({
        let mut path = PathBuf::new();
        $(path.push($x);)+
        path
    });
}

pub fn supply_current_dir_prefix<S: AsRef<str>>(path_name: S) -> String {
    let path_name = path_name.as_ref();

    if path_name.starts_with(".") || path_name.starts_with("/") {
        path_name.to_string()
    } else {
        format!(".{}{}", MAIN_SEPARATOR, path_name)
    }
}

fn into_string<D: Borrow<DirEntry>>(entry: D) -> Option<String> {
    entry
        .borrow()
        .file_name()
        .into_string()
        .ok()
}

pub fn la<P: AsRef<Path>>(path: P) -> Result<Vec<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .filter_map(into_string)
        .collect::<Vec<String>>();
    Ok(dirs)
}

#[cfg(unix)]
pub fn is_recently_accessed<P: AsRef<Path>, D: Borrow<Duration>>(p: P, moratorium: D) -> bool {
    let threshold = UTC::now() - *moratorium.borrow();

    let accessed_time = match p.as_ref().metadata() {
        Ok(m)  => m.atime(),
        Err(_) => unreachable!("Wrong to use this function!!"),
    };

    accessed_time > threshold.timestamp()
}
#[cfg(windows)]
pub fn is_recently_accessed<P: AsRef<Path>, D: Borrow<Duration>>(_p: P, _moratorium: D) -> bool {
    false
}

fn is_hidden_name<S: AsRef<str>>(file_name: S) -> bool {
    let file_name = file_name.as_ref();
    file_name.starts_with(".") && file_name.len() > 1 && file_name != ".."
}

fn is_hidden_for_std(entry: &DirEntry) -> bool {
    into_string(entry).map_or(false, is_hidden_name)
}

fn is_hidden_for_walkdir(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, is_hidden_name)
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !is_hidden_for_walkdir(e))
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .filter_map(|e| e.path().to_str().map(|p| p.to_string()))
        .collect::<BTreeSet<String>>()
}

pub fn potentially_empty_dirs<P: AsRef<Path>>(root: P, ignored_entries: Vec<PathBuf>) -> BTreeSet<PathBuf> {
    fn potentially_empty_dirs(mut result: BTreeSet<PathBuf>, mut target_dirs: VecDeque<PathBuf>, ignored_entries: Vec<PathBuf>) -> BTreeSet<PathBuf> {
        match target_dirs.pop_front() {
            None => result,
            Some(mut target_dir) => {
                let read_result = fs::read_dir(&target_dir);
                let ignore      = read_result.is_err();

                let entries = match read_result {
                    Ok(rd) => rd
                        .filter_map(Result::ok)
                        .collect::<Vec<DirEntry>>(),
                    Err(_) => Vec::new(),
                };
                let include_file_or_hidden_dir = entries
                    .iter()
                    .filter(|e| ignored_entries.iter().all(|ie| *ie != e.path()))
                    .any(|e| e.file_type().ok().map_or(true, |t| t.is_file()) || is_hidden_for_std(e));

                if ignore || include_file_or_hidden_dir {
                    loop {
                        if !(result.remove(&target_dir) && target_dir.pop()) {
                            break;
                        }
                    }
                }

                let dirs = entries
                    .iter()
                    .filter(|e| e.file_type().ok().map_or(false, |t| t.is_dir()) && !is_hidden_for_std(e))
                    .map(|e| e.path())
                    .collect::<BTreeSet<PathBuf>>();
                for dir in dirs.clone().into_iter() {
                    result.insert(dir);
                }

                let mut dirs = dirs.into_iter().collect::<VecDeque<PathBuf>>();
                target_dirs.append(&mut dirs);

                potentially_empty_dirs(result, target_dirs, ignored_entries)
            },
        }
    }

    let mut result     : BTreeSet<PathBuf> = BTreeSet::new();
    let mut target_dirs: VecDeque<PathBuf> = VecDeque::new();

    let root = root.as_ref().to_path_buf();
    result.insert(root.clone());
    target_dirs.push_back(root);

    potentially_empty_dirs(result, target_dirs, ignored_entries)
}

#[test]
fn is_hidden_name_should_return_true() {
    let file_names = [
        ".a",
        ".ab",
        ".abc",
        "..a",
        "...",
    ];
    for file_name in &file_names {
        assert!(is_hidden_name(file_name));
    }
}
#[test]
fn is_hidden_name_should_return_false() {
    let file_names = [
        "",

        ".",
        "..",
        "a",
        "ab",
        "abc",
    ];
    for file_name in &file_names {
        assert!(!is_hidden_name(file_name));
    }
}

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

    use std::collections::BTreeSet;
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::{Path, PathBuf};

    struct Helper {
        d1: String,
        d2: String,
        d3: String,
        d4: String,
        d5: String,
        d6: String,
        f1: String,
        f2: String,
        f3: String,
        f4: String,
    }
    impl Helper {
        fn new(suffix: &str) -> Self {
            Helper {
                d1: format!("directory1_{}" , suffix),
                d2: format!("directory2_{}" , suffix),
                d3: format!("directory3_{}" , suffix),
                d4: format!("directory4_{}" , suffix),
                d5: format!("directory5_{}" , suffix),
                d6: format!(".directory6_{}", suffix),
                f1: format!("file1_{}"      , suffix),
                f2: format!("file2_{}"      , suffix),
                f3: format!("file3_{}"      , suffix),
                f4: format!(".file4_{}"     , suffix),
            }
        }

        fn path_to_d1(&self) -> PathBuf {
            PathBuf::new().join(&self.d1)
        }
        fn path_to_d2(&self) -> PathBuf {
            self.path_to_d1().join(&self.d2)
        }
        fn path_to_d3(&self) -> PathBuf {
            self.path_to_d2().join(&self.d3)
        }
        fn path_to_d4(&self) -> PathBuf {
            self.path_to_d3().join(&self.d4)
        }
        fn path_to_d5(&self) -> PathBuf {
            self.path_to_d1().join(&self.d5)
        }
        fn path_to_d6(&self) -> PathBuf {
            self.path_to_d1().join(&self.d6)
        }

        fn path_to_f1(&self) -> PathBuf {
            self.path_to_d1().join(&self.f1)
        }
        fn path_to_f2(&self) -> PathBuf {
            self.path_to_d2().join(&self.f2)
        }
        fn path_to_f3(&self) -> PathBuf {
            self.path_to_d3().join(&self.f3)
        }
        fn path_to_f4(&self) -> PathBuf {
            self.path_to_d5().join(&self.f4)
        }

        fn remove_dirs_and_files(&self) {
            fs::remove_dir_all(self.path_to_d1()).ok();
        }

        fn create_dirs_and_files(&self) {
            self.remove_dirs_and_files();

            fs::create_dir_all(self.path_to_d4()).ok();
            fs::create_dir_all(self.path_to_d5()).ok();
            fs::create_dir_all(self.path_to_d6()).ok();

            let mut f = File::create(self.path_to_f1()).unwrap();
            f.write("\n".as_ref()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f2()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f3()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f4()).ok();
        }
    }

    #[test]
    fn path_buf_macro_should_create_path_buf() {
        let paths = [
            (Path::new("path").to_path_buf()          , path_buf!["path"              ]),
            (Path::new("path").join("to")             , path_buf!["path", "to"        ]),
            (Path::new("path").join("to").join("file"), path_buf!["path", "to", "file"]),
        ];
        for &(ref correct, ref calculated) in &paths {
            assert_eq!(correct, calculated);
        }
    }

    #[test]
    fn supply_current_dir_prefix_should_return_added() {
        let path_names = [
            ("./a"  , "a"  ),
            ("./a/" , "a/" ),
            ("./a/b", "a/b"),
        ];
        for &(correct, input) in &path_names {
            assert_eq!(correct.to_string(), supply_current_dir_prefix(input));
        }
    }
    #[test]
    fn supply_current_dir_prefix_should_return_as_it_is() {
        let path_names = [
            "/",
            "/a",
            ".",
            "./",
            "./a",
            "././a",
        ];
        for path_name in &path_names {
            assert_eq!(path_name.to_string(), supply_current_dir_prefix(path_name))
        }
    }

    #[test]
    fn la_should_return_ok() {
        fn to_btree_set(vec: Vec<String>) -> BTreeSet<String> {
            vec.into_iter().collect::<BTreeSet<String>>()
        }

        let helper = Helper::new("la_Ok");
        helper.create_dirs_and_files();

        let data_set = vec![
            (vec![helper.d2.clone(), helper.d5.clone(), helper.d6.clone(), helper.f1.clone()], helper.path_to_d1()),
            (vec![helper.d3.clone(), helper.f2.clone()]                                      , helper.path_to_d2()),
            (vec![helper.d4.clone(), helper.f3.clone()]                                      , helper.path_to_d3()),
            (Vec::new()                                                                      , helper.path_to_d4()),
            (vec![helper.f4.clone()]                                                         , helper.path_to_d5()),
            (Vec::new()                                                                      , helper.path_to_d6()),
        ];

        for (correct, target_dir) in data_set.into_iter() {
            assert_eq!(to_btree_set(correct), to_btree_set(la(target_dir).unwrap()));
        }

        helper.remove_dirs_and_files();
    }

    #[test]
    fn walk_dir_should_return_b_tree_set() {
        let helper = Helper::new("walk_dir_BTreeSet");
        helper.create_dirs_and_files();

        let mut correct = BTreeSet::new();
        let files = [helper.path_to_f1(), helper.path_to_f2(), helper.path_to_f3()];
        for file in &files {
            correct.insert(file.to_str().unwrap().to_string());
        }

        assert_eq!(correct, walk_dir(helper.path_to_d1()));

        helper.remove_dirs_and_files();
    }

    #[test]
    fn potentially_empty_dirs_should_return_btree_set() {
        let helper = Helper::new("potentially_empty_dirs_BTreeSet");
        helper.create_dirs_and_files();

        let root = helper.path_to_d1();

        let mut correct = BTreeSet::new();
        correct.insert(helper.path_to_d4());
        let mut ignored_files = Vec::new();
        let data_set = vec![
            (helper.path_to_d3(), helper.path_to_f3()),
            (helper.path_to_d2(), helper.path_to_f2()),
            (helper.path_to_d5(), helper.path_to_f4()),
        ];
        for (part_of_correct, ignored_file) in data_set.into_iter() {
            correct.insert(part_of_correct);
            ignored_files.push(ignored_file);
            assert_eq!(correct, potentially_empty_dirs(&root, ignored_files.clone()));
        }

        correct.clear();
        correct.insert(helper.path_to_d4());
        let data_set = vec![
            (helper.path_to_d4(), None),
            (helper.path_to_d3(), Some(helper.path_to_f3())),
            (helper.path_to_d2(), Some(helper.path_to_f2())),
            (helper.path_to_d5(), Some(helper.path_to_f4())),
        ];
        for (part_of_correct, removed_file) in data_set.into_iter() {
            correct.insert(part_of_correct);
            if let Some(file) = removed_file {
                fs::remove_file(file).ok();
            }
            assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));
        }

        helper.remove_dirs_and_files();
    }
}
<commit_msg>[Refactoring] Create trait "DirEntryExt"<commit_after>extern crate chrono;
extern crate walkdir;

use self::chrono::{Duration, UTC};
use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};

use std::borrow::Borrow;
use std::collections::{BTreeSet, VecDeque};
use std::fs::{self, DirEntry};
use std::io::Error as IoError;
use std::os::unix::fs::MetadataExt;
use std::path::{MAIN_SEPARATOR, Path, PathBuf};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),+) => ({
        let mut path = PathBuf::new();
        $(path.push($x);)+
        path
    });
}

fn is_hidden_name(file_name: &str) -> bool {
    file_name.starts_with(".") && file_name.len() > 1 && file_name != ".."
}

trait DirEntryExt {
    fn file_name_string(&self) -> Option<String> {
        unimplemented!();
    }

    fn is_hidden(&self) -> bool;
}
impl DirEntryExt for DirEntry {
    fn file_name_string(&self) -> Option<String> {
        self
            .file_name()
            .into_string()
            .ok()
    }

    fn is_hidden(&self) -> bool {
        self
            .file_name()
            .to_str()
            .map_or(false, is_hidden_name)
    }
}
impl DirEntryExt for WalkDirEntry {
    fn is_hidden(&self) -> bool {
        self
            .file_name()
            .to_str()
            .map_or(false, is_hidden_name)
    }
}

pub fn supply_current_dir_prefix<S: AsRef<str>>(path_name: S) -> String {
    let path_name = path_name.as_ref();

    if path_name.starts_with(".") || path_name.starts_with("/") {
        path_name.to_string()
    } else {
        format!(".{}{}", MAIN_SEPARATOR, path_name)
    }
}

pub fn la<P: AsRef<Path>>(path: P) -> Result<Vec<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .filter_map(|e| e.file_name_string())
        .collect::<Vec<String>>();
    Ok(dirs)
}

#[cfg(unix)]
pub fn is_recently_accessed<P: AsRef<Path>, D: Borrow<Duration>>(p: P, moratorium: D) -> bool {
    let threshold = UTC::now() - *moratorium.borrow();

    let accessed_time = match p.as_ref().metadata() {
        Ok(m)  => m.atime(),
        Err(_) => unreachable!("Wrong to use this function!!"),
    };

    accessed_time > threshold.timestamp()
}
#[cfg(windows)]
pub fn is_recently_accessed<P: AsRef<Path>, D: Borrow<Duration>>(_p: P, _moratorium: D) -> bool {
    false
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(|e| !e.is_hidden())
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .filter_map(|e| e.path().to_str().map(|p| p.to_string()))
        .collect::<BTreeSet<String>>()
}

pub fn potentially_empty_dirs<P: AsRef<Path>>(root: P, ignored_entries: Vec<PathBuf>) -> BTreeSet<PathBuf> {
    fn potentially_empty_dirs(mut result: BTreeSet<PathBuf>, mut target_dirs: VecDeque<PathBuf>, ignored_entries: Vec<PathBuf>) -> BTreeSet<PathBuf> {
        match target_dirs.pop_front() {
            None => result,
            Some(mut target_dir) => {
                let read_result = fs::read_dir(&target_dir);
                let ignore      = read_result.is_err();

                let entries = match read_result {
                    Ok(rd) => rd
                        .filter_map(Result::ok)
                        .collect::<Vec<DirEntry>>(),
                    Err(_) => Vec::new(),
                };
                let include_file_or_hidden_dir = entries
                    .iter()
                    .filter(|e| ignored_entries.iter().all(|ie| *ie != e.path()))
                    .any(|e| e.file_type().ok().map_or(true, |t| t.is_file()) || e.is_hidden());

                if ignore || include_file_or_hidden_dir {
                    loop {
                        if !(result.remove(&target_dir) && target_dir.pop()) {
                            break;
                        }
                    }
                }

                let dirs = entries
                    .iter()
                    .filter(|e| e.file_type().ok().map_or(false, |t| t.is_dir()) && !e.is_hidden())
                    .map(|e| e.path())
                    .collect::<BTreeSet<PathBuf>>();
                for dir in dirs.clone().into_iter() {
                    result.insert(dir);
                }

                let mut dirs = dirs.into_iter().collect::<VecDeque<PathBuf>>();
                target_dirs.append(&mut dirs);

                potentially_empty_dirs(result, target_dirs, ignored_entries)
            },
        }
    }

    let mut result     : BTreeSet<PathBuf> = BTreeSet::new();
    let mut target_dirs: VecDeque<PathBuf> = VecDeque::new();

    let root = root.as_ref().to_path_buf();
    result.insert(root.clone());
    target_dirs.push_back(root);

    potentially_empty_dirs(result, target_dirs, ignored_entries)
}

#[test]
fn is_hidden_name_should_return_true() {
    let file_names = [
        ".a",
        ".ab",
        ".abc",
        "..a",
        "...",
    ];
    for file_name in &file_names {
        assert!(is_hidden_name(file_name));
    }
}
#[test]
fn is_hidden_name_should_return_false() {
    let file_names = [
        "",

        ".",
        "..",
        "a",
        "ab",
        "abc",
    ];
    for file_name in &file_names {
        assert!(!is_hidden_name(file_name));
    }
}

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

    use std::collections::BTreeSet;
    use std::fs::{self, File};
    use std::io::Write;
    use std::path::{Path, PathBuf};

    struct Helper {
        d1: String,
        d2: String,
        d3: String,
        d4: String,
        d5: String,
        d6: String,
        f1: String,
        f2: String,
        f3: String,
        f4: String,
    }
    impl Helper {
        fn new(suffix: &str) -> Self {
            Helper {
                d1: format!("directory1_{}" , suffix),
                d2: format!("directory2_{}" , suffix),
                d3: format!("directory3_{}" , suffix),
                d4: format!("directory4_{}" , suffix),
                d5: format!("directory5_{}" , suffix),
                d6: format!(".directory6_{}", suffix),
                f1: format!("file1_{}"      , suffix),
                f2: format!("file2_{}"      , suffix),
                f3: format!("file3_{}"      , suffix),
                f4: format!(".file4_{}"     , suffix),
            }
        }

        fn path_to_d1(&self) -> PathBuf {
            PathBuf::new().join(&self.d1)
        }
        fn path_to_d2(&self) -> PathBuf {
            self.path_to_d1().join(&self.d2)
        }
        fn path_to_d3(&self) -> PathBuf {
            self.path_to_d2().join(&self.d3)
        }
        fn path_to_d4(&self) -> PathBuf {
            self.path_to_d3().join(&self.d4)
        }
        fn path_to_d5(&self) -> PathBuf {
            self.path_to_d1().join(&self.d5)
        }
        fn path_to_d6(&self) -> PathBuf {
            self.path_to_d1().join(&self.d6)
        }

        fn path_to_f1(&self) -> PathBuf {
            self.path_to_d1().join(&self.f1)
        }
        fn path_to_f2(&self) -> PathBuf {
            self.path_to_d2().join(&self.f2)
        }
        fn path_to_f3(&self) -> PathBuf {
            self.path_to_d3().join(&self.f3)
        }
        fn path_to_f4(&self) -> PathBuf {
            self.path_to_d5().join(&self.f4)
        }

        fn remove_dirs_and_files(&self) {
            fs::remove_dir_all(self.path_to_d1()).ok();
        }

        fn create_dirs_and_files(&self) {
            self.remove_dirs_and_files();

            fs::create_dir_all(self.path_to_d4()).ok();
            fs::create_dir_all(self.path_to_d5()).ok();
            fs::create_dir_all(self.path_to_d6()).ok();

            let mut f = File::create(self.path_to_f1()).unwrap();
            f.write("\n".as_ref()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f2()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f3()).ok();
            fs::copy(self.path_to_f1(), self.path_to_f4()).ok();
        }
    }

    #[test]
    fn path_buf_macro_should_create_path_buf() {
        let paths = [
            (Path::new("path").to_path_buf()          , path_buf!["path"              ]),
            (Path::new("path").join("to")             , path_buf!["path", "to"        ]),
            (Path::new("path").join("to").join("file"), path_buf!["path", "to", "file"]),
        ];
        for &(ref correct, ref calculated) in &paths {
            assert_eq!(correct, calculated);
        }
    }

    #[test]
    fn supply_current_dir_prefix_should_return_added() {
        let path_names = [
            ("./a"  , "a"  ),
            ("./a/" , "a/" ),
            ("./a/b", "a/b"),
        ];
        for &(correct, input) in &path_names {
            assert_eq!(correct.to_string(), supply_current_dir_prefix(input));
        }
    }
    #[test]
    fn supply_current_dir_prefix_should_return_as_it_is() {
        let path_names = [
            "/",
            "/a",
            ".",
            "./",
            "./a",
            "././a",
        ];
        for path_name in &path_names {
            assert_eq!(path_name.to_string(), supply_current_dir_prefix(path_name))
        }
    }

    #[test]
    fn la_should_return_ok() {
        fn to_btree_set(vec: Vec<String>) -> BTreeSet<String> {
            vec.into_iter().collect::<BTreeSet<String>>()
        }

        let helper = Helper::new("la_Ok");
        helper.create_dirs_and_files();

        let data_set = vec![
            (vec![helper.d2.clone(), helper.d5.clone(), helper.d6.clone(), helper.f1.clone()], helper.path_to_d1()),
            (vec![helper.d3.clone(), helper.f2.clone()]                                      , helper.path_to_d2()),
            (vec![helper.d4.clone(), helper.f3.clone()]                                      , helper.path_to_d3()),
            (Vec::new()                                                                      , helper.path_to_d4()),
            (vec![helper.f4.clone()]                                                         , helper.path_to_d5()),
            (Vec::new()                                                                      , helper.path_to_d6()),
        ];

        for (correct, target_dir) in data_set.into_iter() {
            assert_eq!(to_btree_set(correct), to_btree_set(la(target_dir).unwrap()));
        }

        helper.remove_dirs_and_files();
    }

    #[test]
    fn walk_dir_should_return_b_tree_set() {
        let helper = Helper::new("walk_dir_BTreeSet");
        helper.create_dirs_and_files();

        let mut correct = BTreeSet::new();
        let files = [helper.path_to_f1(), helper.path_to_f2(), helper.path_to_f3()];
        for file in &files {
            correct.insert(file.to_str().unwrap().to_string());
        }

        assert_eq!(correct, walk_dir(helper.path_to_d1()));

        helper.remove_dirs_and_files();
    }

    #[test]
    fn potentially_empty_dirs_should_return_btree_set() {
        let helper = Helper::new("potentially_empty_dirs_BTreeSet");
        helper.create_dirs_and_files();

        let root = helper.path_to_d1();

        let mut correct = BTreeSet::new();
        correct.insert(helper.path_to_d4());
        let mut ignored_files = Vec::new();
        let data_set = vec![
            (helper.path_to_d3(), helper.path_to_f3()),
            (helper.path_to_d2(), helper.path_to_f2()),
            (helper.path_to_d5(), helper.path_to_f4()),
        ];
        for (part_of_correct, ignored_file) in data_set.into_iter() {
            correct.insert(part_of_correct);
            ignored_files.push(ignored_file);
            assert_eq!(correct, potentially_empty_dirs(&root, ignored_files.clone()));
        }

        correct.clear();
        correct.insert(helper.path_to_d4());
        let data_set = vec![
            (helper.path_to_d4(), None),
            (helper.path_to_d3(), Some(helper.path_to_f3())),
            (helper.path_to_d2(), Some(helper.path_to_f2())),
            (helper.path_to_d5(), Some(helper.path_to_f4())),
        ];
        for (part_of_correct, removed_file) in data_set.into_iter() {
            correct.insert(part_of_correct);
            if let Some(file) = removed_file {
                fs::remove_file(file).ok();
            }
            assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));
        }

        helper.remove_dirs_and_files();
    }
}
<|endoftext|>


<commit_before>//! This is the `custom types` module for Xtensis.

// This file is part of Xtensis.

// This is the Xtensis text editor; it edits text.
// Copyright (C) 2016-2017  The Xtensis Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

/// ID of a Buffer.
pub type BufferID = String,
<commit_msg>Fix typo in utils/types<commit_after>//! This is the `custom types` module for Xtensis.

// This file is part of Xtensis.

// This is the Xtensis text editor; it edits text.
// Copyright (C) 2016-2017  The Xtensis Developers

// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.

/// ID of a Buffer.
pub type BufferID = String;
<|endoftext|>


<commit_before>//! Provide syntax highlighting via [Syntect].
//!
//! [Syntect]: https://docs.rs/syntect/1.0.0/syntect/

// Standard library
use std::borrow::Cow;
use std::default::Default;
use std::collections::HashMap;
use std::str;

// Third party
use quick_xml::{XmlReader, XmlWriter, Element, Event};
use syntect::html::highlighted_snippet_for_string;
use syntect::highlighting::Theme;
use syntect::parsing::{SyntaxDefinition, SyntaxSet};

/// A `Language` is a `String` representing a code highlighting language.
type Language = String;

/// Define XML parsing states of interest for highlighting.
///
/// We use these in conjunction with `ParseEvent`s to drive a state machine
/// which tracks whether a stream of `quick_xml::Event`s indicates the presence
/// of a code block to be highlighted.
#[derive(Clone, Debug, PartialEq)]
enum ParseState {
    /// Not in a code block at all.
    NotInBlock,
    /// Possibly the start of a highlight block, with the language as payload.
    MaybeStartBlock(Language),
    /// The start of the code block has been confirmed; highlight next text node.
    WillStartCodeBlock(Language),
    /// In a code block; use the content for highlighting.
    InCodeBlock(Language),
}

/// Define XML parsing events of interest for highlighting.
///
/// We don't care at all about any other items for this specific scenario; we
/// use these in conjunction with the `ParseState` to drive the state  machine
/// described there.
#[derive(Debug)]
enum ParseEvent {
    // Starting a `<pre>`; optionally specifying a language.
    StartPre(Option<Language>),
    // Starting a `<code>`.
    StartCode,
    // Ending a `<code>`.
    EndCode,
    Text,
    Whitespace,
    Other,
}

impl ParseState {
    /// Get the next `ParseState` given current `ParseState` and a `ParseEvent`.
    fn next(self, event: ParseEvent) -> ParseState {
        use self::ParseState::*;
        use self::ParseEvent::*;

        match (self, event) {
            (NotInBlock, StartPre(Some(language))) => MaybeStartBlock(language),
            (MaybeStartBlock(language), Whitespace) => MaybeStartBlock(language),
            (MaybeStartBlock(language), StartCode) => WillStartCodeBlock(language),
            (WillStartCodeBlock(language), Text) |
            (WillStartCodeBlock(language), Whitespace) => InCodeBlock(language),
            (InCodeBlock(_), EndCode) => NotInBlock,
            (_, _) => NotInBlock,
        }
    }
}

impl Default for ParseState {
    fn default() -> ParseState {
        ParseState::NotInBlock
    }
}

impl<'e> From<&'e Event> for ParseEvent {
    fn from(event: &'e Event) -> ParseEvent {
        // TODO @1.15: remove `'static`.
        const PRE: &'static [u8] = b"pre";
        const CODE: &'static [u8] = b"code";
        const CLASS: &'static [u8] = b"class";
        const WHITE_SPACE: &'static [u8] = b"";

        match *event {
            Event::Start(ref element) => {
                match element.name() {
                    PRE => {
                        let maybe_class_attr = element.attributes()
                            .map(|attr| attr.unwrap())
                            .filter(|&(attr, _value)| attr == CLASS)
                            .next();

                        if let Some((_attr, value)) = maybe_class_attr {
                            match str::from_utf8(value) {
                                Ok(lang) => ParseEvent::StartPre(Some(lang.to_string())),
                                Err(_) => ParseEvent::StartPre(None),
                            }
                        } else {
                            ParseEvent::StartPre(None)
                        }
                    }
                    CODE => ParseEvent::StartCode,
                    _ => ParseEvent::Other,
                }
            }
            Event::End(ref element) => {
                match element.name() {
                    CODE => ParseEvent::EndCode,
                    _ => ParseEvent::Other,
                }
            }
            Event::Text(ref element) => {
                match element.name() {
                    WHITE_SPACE => ParseEvent::Whitespace,
                    _ => ParseEvent::Text,
                }
            }
            _ => ParseEvent::Other,
        }
    }
}

/// Highlight all code blocks in a block of HTML.
///
/// Assumes that the blocks to be highlighted are in the following basic format:
///
/// ```html
/// <pre class="rust">
///   <code>
///     pub fn syntax_highlight(html_string: String) -> String {
///         // implementation details
///     }
///   </code>
/// </pre>
/// ```
///
/// The `class` attribute value from the `pre` tag defines the language used to
/// highlight the code.
///
/// Note that any `html_string` will do; if it cannot be parsed as XML, it will
/// simply be returned unchanged; and if there are no code blocks to highlight,
/// it will also be returned unchanged.
pub fn syntax_highlight(html_string: String, theme: &Theme) -> String {
    let ss = SyntaxSet::load_defaults_nonewlines();
    let mut syntax_definitions = HashMap::<Language, SyntaxDefinition>::new();

    let mut writer = XmlWriter::new(Vec::<u8>::new());
    let mut state = ParseState::default();

    for event in XmlReader::from(html_string.as_str()) {
        let event = match event {
            Ok(event) => event,
            Err(_) => continue
        };

        let parse_event = ParseEvent::from(&event);
        state = ParseState::next(state, parse_event);

        let language = match state {
            ParseState::InCodeBlock(ref language) => language.clone(),
            _ => {
                assert!(writer.write(event).is_ok());
                continue;
            }
        };

        let unescaped_content = match event.element().unescaped_content().map(Cow::into_owned) {
            Ok(content) => content,
            Err(_) => {
                assert!(writer.write(event).is_ok());
                continue;
            }
        };

        let content_to_highlight = match str::from_utf8(&unescaped_content) {
            Ok(utf8_str) => utf8_str,
            Err(_) => {
                assert!(writer.write(event).is_ok());
                continue;
            }
        };

        let syntax_key = language.clone();
        let syntax_definition = syntax_definitions.entry(syntax_key).or_insert({
            match ss.find_syntax_by_token(&language) {
                Some(valid_syntax) => valid_syntax.clone(),
                None => {
                    assert!(writer.write(event).is_ok());
                    continue;
                }
            }
        });

        let highlighted =
            highlighted_snippet_for_string(content_to_highlight, syntax_definition, &theme);

        let text = Element::new(highlighted);
        assert!(writer.write(Event::Text(text)).is_ok());
    }

    String::from_utf8(writer.into_inner()).unwrap_or(html_string)
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_parse_state() {
        use super::ParseState;
        use super::ParseEvent;

        let lang = "rust";

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::StartPre(Some(lang.to_string()))),
                   ParseState::MaybeStartBlock(lang.to_string()));

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::EndCode),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::Other),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::StartCode),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::StartCode),
                   ParseState::WillStartCodeBlock(lang.to_string()));

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::Text),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::EndCode),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string())
                       .next(ParseEvent::StartPre(Some(lang.to_string()))),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::Other),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::WillStartCodeBlock(lang.to_string()).next(ParseEvent::Text),
                   ParseState::InCodeBlock(lang.to_string()));
    }
}
<commit_msg>Avoid copying content in syntax_highlight.<commit_after>//! Provide syntax highlighting via [Syntect].
//!
//! [Syntect]: https://docs.rs/syntect/1.0.0/syntect/

// Standard library
use std::default::Default;
use std::collections::HashMap;
use std::str;

// Third party
use quick_xml::{XmlReader, XmlWriter, Element, Event};
use syntect::html::highlighted_snippet_for_string;
use syntect::highlighting::Theme;
use syntect::parsing::{SyntaxDefinition, SyntaxSet};

/// A `Language` is a `String` representing a code highlighting language.
type Language = String;

/// Define XML parsing states of interest for highlighting.
///
/// We use these in conjunction with `ParseEvent`s to drive a state machine
/// which tracks whether a stream of `quick_xml::Event`s indicates the presence
/// of a code block to be highlighted.
#[derive(Clone, Debug, PartialEq)]
enum ParseState {
    /// Not in a code block at all.
    NotInBlock,
    /// Possibly the start of a highlight block, with the language as payload.
    MaybeStartBlock(Language),
    /// The start of the code block has been confirmed; highlight next text node.
    WillStartCodeBlock(Language),
    /// In a code block; use the content for highlighting.
    InCodeBlock(Language),
}

/// Define XML parsing events of interest for highlighting.
///
/// We don't care at all about any other items for this specific scenario; we
/// use these in conjunction with the `ParseState` to drive the state  machine
/// described there.
#[derive(Debug)]
enum ParseEvent {
    // Starting a `<pre>`; optionally specifying a language.
    StartPre(Option<Language>),
    // Starting a `<code>`.
    StartCode,
    // Ending a `<code>`.
    EndCode,
    Text,
    Whitespace,
    Other,
}

impl ParseState {
    /// Get the next `ParseState` given current `ParseState` and a `ParseEvent`.
    fn next(self, event: ParseEvent) -> ParseState {
        use self::ParseState::*;
        use self::ParseEvent::*;

        match (self, event) {
            (NotInBlock, StartPre(Some(language))) => MaybeStartBlock(language),
            (MaybeStartBlock(language), Whitespace) => MaybeStartBlock(language),
            (MaybeStartBlock(language), StartCode) => WillStartCodeBlock(language),
            (WillStartCodeBlock(language), Text) |
            (WillStartCodeBlock(language), Whitespace) => InCodeBlock(language),
            (InCodeBlock(_), EndCode) => NotInBlock,
            (_, _) => NotInBlock,
        }
    }
}

impl Default for ParseState {
    fn default() -> ParseState {
        ParseState::NotInBlock
    }
}

impl<'e> From<&'e Event> for ParseEvent {
    fn from(event: &'e Event) -> ParseEvent {
        // TODO @1.15: remove `'static`.
        const PRE: &'static [u8] = b"pre";
        const CODE: &'static [u8] = b"code";
        const CLASS: &'static [u8] = b"class";
        const WHITE_SPACE: &'static [u8] = b"";

        match *event {
            Event::Start(ref element) => {
                match element.name() {
                    PRE => {
                        let maybe_class_attr = element.attributes()
                            .map(|attr| attr.unwrap())
                            .filter(|&(attr, _value)| attr == CLASS)
                            .next();

                        if let Some((_attr, value)) = maybe_class_attr {
                            match str::from_utf8(value) {
                                Ok(lang) => ParseEvent::StartPre(Some(lang.to_string())),
                                Err(_) => ParseEvent::StartPre(None),
                            }
                        } else {
                            ParseEvent::StartPre(None)
                        }
                    }
                    CODE => ParseEvent::StartCode,
                    _ => ParseEvent::Other,
                }
            }
            Event::End(ref element) => {
                match element.name() {
                    CODE => ParseEvent::EndCode,
                    _ => ParseEvent::Other,
                }
            }
            Event::Text(ref element) => {
                match element.name() {
                    WHITE_SPACE => ParseEvent::Whitespace,
                    _ => ParseEvent::Text,
                }
            }
            _ => ParseEvent::Other,
        }
    }
}

/// Highlight all code blocks in a block of HTML.
///
/// Assumes that the blocks to be highlighted are in the following basic format:
///
/// ```html
/// <pre class="rust">
///   <code>
///     pub fn syntax_highlight(html_string: String) -> String {
///         // implementation details
///     }
///   </code>
/// </pre>
/// ```
///
/// The `class` attribute value from the `pre` tag defines the language used to
/// highlight the code.
///
/// Note that any `html_string` will do; if it cannot be parsed as XML, it will
/// simply be returned unchanged; and if there are no code blocks to highlight,
/// it will also be returned unchanged.
pub fn syntax_highlight(html_string: String, theme: &Theme) -> String {
    let ss = SyntaxSet::load_defaults_nonewlines();
    let mut syntax_definitions = HashMap::<Language, SyntaxDefinition>::new();

    let mut writer = XmlWriter::new(Vec::<u8>::new());
    let mut state = ParseState::default();

    for event in XmlReader::from(html_string.as_str()) {
        let event = match event {
            Ok(event) => event,
            Err(_) => continue
        };

        let parse_event = ParseEvent::from(&event);
        state = ParseState::next(state, parse_event);

        if let ParseState::InCodeBlock(ref language) = state {
            if let Ok(unescaped_content) = event.element().unescaped_content() {
                if let Ok(content_to_highlight) = str::from_utf8(&unescaped_content) {
                    if let Some(valid_syntax) = ss.find_syntax_by_token(&language) {
                        let syntax_definition =
                            syntax_definitions.entry(language.clone())
                                              .or_insert_with(|| valid_syntax.clone());

                        let highlighted = highlighted_snippet_for_string(content_to_highlight,
                                                                         syntax_definition,
                                                                         &theme);
                        let text = Element::new(highlighted);
                        assert!(writer.write(Event::Text(text)).is_ok());
                        continue;
                    }
                }
            }
        }

        // Syntax highlighting did not succeed, so just write the original event.
        assert!(writer.write(event).is_ok());
    }

    String::from_utf8(writer.into_inner()).unwrap_or(html_string)
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_parse_state() {
        use super::ParseState;
        use super::ParseEvent;

        let lang = "rust";

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::StartPre(Some(lang.to_string()))),
                   ParseState::MaybeStartBlock(lang.to_string()));

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::EndCode),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::Other),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::NotInBlock.next(ParseEvent::StartCode),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::StartCode),
                   ParseState::WillStartCodeBlock(lang.to_string()));

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::Text),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::EndCode),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string())
                       .next(ParseEvent::StartPre(Some(lang.to_string()))),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::MaybeStartBlock(lang.to_string()).next(ParseEvent::Other),
                   ParseState::NotInBlock);

        assert_eq!(ParseState::WillStartCodeBlock(lang.to_string()).next(ParseEvent::Text),
                   ParseState::InCodeBlock(lang.to_string()));
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! xs_return {
    ($ctx:ident, $( $val:expr ),*) => {{
        $ctx.st_prepush();
        $( $ctx.st_push($val); )*
        $ctx.st_putback();
        return;
    }}
}

/// Define Perl modules and packages.
///
/// First form of this macro is used to define a Perl package inside a module. Each invocation
/// should contain only one package and there should be only one such invocation per Rust module.
///
/// ```
/// mod acme {
///     xs! {
///         package Acme;
///         sub foo(ctx) { /* code */ }
///     }
/// }
/// ```
///
/// Second form is used to generate bootstrap function used by Perl to intialize XS module. Each
/// crate should contain exactly one invocation in this form:
///
/// ```
/// xs! {
///     bootstrap boot_Acme;
///     use acme;
/// }
/// ```
///
/// Function name given to `bootstrap` keyword must start with `boot_` followed by the Perl module
/// name.
#[macro_export]
macro_rules! xs {
    (
        package $pkg:path ;
        $( sub $name:ident ($ctx:ident) $body:block )*
    ) => (
        $(
            pthx! {
                fn $name (pthx, _cv: *mut $crate::raw::CV) {
                    let mut $ctx = $crate::context::Context::new(&pthx);
                    $body
                }
            }
        )*

        pub const PERL_XS: &'static [ (&'static str, $crate::raw::XSUBADDR_t) ] = &[
            $(
                (
                    concat!(stringify!($pkg), "::", stringify!($name)),
                    $name as $crate::raw::XSUBADDR_t,
                )
            ),*
        ];
    );

    (
        bootstrap $boot:ident;
        $( use $( $name:ident )::+ ; )*
    ) => (
        pthx! {
            #[no_mangle]
            #[allow(non_snake_case)]
            fn $boot (pthx, _cv: *mut $crate::raw::CV) {
                let mut ctx = $crate::context::Context::new(&pthx);
                $(
                    for &(subname, subptr) in $( $name )::*::PERL_XS {
                        let cname = ::std::ffi::CString::new(subname).unwrap();
                        ctx.new_xs(&cname, subptr);
                    }
                )*

                xs_return!(ctx, 1 as $crate::raw::IV);
            }
        }
    );
}

#[macro_export]
macro_rules! cstr {
    ($e:expr) => (&::std::ffi::CString::new($e).unwrap())
}
<commit_msg>Allow empty return.<commit_after>#[macro_export]
macro_rules! xs_return {
    ($ctx:ident) => {{
        $ctx.st_prepush();
        $ctx.st_putback();
    }};

    ($ctx:ident, $( $val:expr ),*) => {{
        $ctx.st_prepush();
        $( $ctx.st_push($val); )*
        $ctx.st_putback();
        return;
    }}
}

/// Define Perl modules and packages.
///
/// First form of this macro is used to define a Perl package inside a module. Each invocation
/// should contain only one package and there should be only one such invocation per Rust module.
///
/// ```
/// mod acme {
///     xs! {
///         package Acme;
///         sub foo(ctx) { /* code */ }
///     }
/// }
/// ```
///
/// Second form is used to generate bootstrap function used by Perl to intialize XS module. Each
/// crate should contain exactly one invocation in this form:
///
/// ```
/// xs! {
///     bootstrap boot_Acme;
///     use acme;
/// }
/// ```
///
/// Function name given to `bootstrap` keyword must start with `boot_` followed by the Perl module
/// name.
#[macro_export]
macro_rules! xs {
    (
        package $pkg:path ;
        $( sub $name:ident ($ctx:ident) $body:block )*
    ) => (
        $(
            pthx! {
                fn $name (pthx, _cv: *mut $crate::raw::CV) {
                    let mut $ctx = $crate::context::Context::new(&pthx);
                    $body
                }
            }
        )*

        pub const PERL_XS: &'static [ (&'static str, $crate::raw::XSUBADDR_t) ] = &[
            $(
                (
                    concat!(stringify!($pkg), "::", stringify!($name)),
                    $name as $crate::raw::XSUBADDR_t,
                )
            ),*
        ];
    );

    (
        bootstrap $boot:ident;
        $( use $( $name:ident )::+ ; )*
    ) => (
        pthx! {
            #[no_mangle]
            #[allow(non_snake_case)]
            fn $boot (pthx, _cv: *mut $crate::raw::CV) {
                let mut ctx = $crate::context::Context::new(&pthx);
                $(
                    for &(subname, subptr) in $( $name )::*::PERL_XS {
                        let cname = ::std::ffi::CString::new(subname).unwrap();
                        ctx.new_xs(&cname, subptr);
                    }
                )*

                xs_return!(ctx, 1 as $crate::raw::IV);
            }
        }
    );
}

#[macro_export]
macro_rules! cstr {
    ($e:expr) => (&::std::ffi::CString::new($e).unwrap())
}
<|endoftext|>


<commit_before>//use core::slice;

#[cfg(not(feature="unsafe"))]
macro_rules! fast_ref {
   (($slice : expr)[$index: expr]) => (
       &(&$slice)[$index]
   );
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_inner {
   (($slice : expr)[$index: expr]) => (
       (&$slice)[$index]
   );
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_inner {
   (($slice : expr)[$index: expr]) => (
       (&$slice)[$index]
   );
}
/*
#[cfg(not(feature="unsafe"))]
macro_rules! fast_slice {
   (($slice : expr)[$index: expr]) => (
       ($slice.slice())[$index]
   );
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_slice_mut {
   (($slice : expr)[$index: expr]) => (
       ($slice.slice_mut())[$index]
   );
}
*/

#[cfg(not(feature="unsafe"))]
macro_rules! fast {
   (($slice : expr)[$index: expr]) => (
       (&$slice)[$index]
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       &($slice)[$start .. $end]
   );
   (($slice : expr)[$start: expr ;]) => (
       &($slice)[$start .. ]
   );
   (($slice : expr)[; $end]) => (
       &($slice)[.. $end ]
   );
}
#[cfg(not(feature="unsafe"))]
macro_rules! fast_uninitialized {
    [$size : expr] => ([0; $size]);
    [$def_value : expr ; $size : expr] => ([$def_value; $size]);
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_mut {
   (($slice : expr)[$index: expr]) => (
       *&mut($slice)[$index]
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       &mut $slice[$start..$end]
   );
   (($slice : expr)[$start: expr ;]) => (
       &mut $slice[$start..]
   );
   (($slice : expr)[; $end]) => (
       &mut $slice[..$end]
   );
}

#[cfg(feature="unsafe")]
#[allow(unused_unsafe)]
macro_rules! fast_ref {
   (($slice : expr)[$index: expr]) => (
       unsafe{$slice.get_unchecked($index)}
   );
}

#[cfg(feature="unsafe")]
macro_rules! fast_inner {
   (($slice : expr)[$index: expr]) => (
       *$slice.get_unchecked($index)
   );
}
/*
#[cfg(feature="unsafe")]
macro_rules! fast_slice {
   (($slice : expr)[$index: expr]) => (
       unsafe{*$slice.slice().get_unchecked($index)}
   );
}
*/
#[cfg(feature="unsafe")]
macro_rules! fast {
   (($slice : expr)[$index: expr]) => (
       unsafe{*$slice.get_unchecked($index)}
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       unsafe{::core::slice::from_raw_parts(($slice).as_ptr().offset($start as isize), $end - $start)};
   );
   (($slice : expr)[$start: expr ;]) => (
       unsafe{::core::slice::from_raw_parts(($slice).as_ptr().offset($start as isize), $slice.len() - $start)};
   );
   (($slice : expr)[; $end]) => (
       unsafe{::core::slice::from_raw_parts(($slice).as_ptr(), $slice.len())};
   );
}

macro_rules! fast_slice {
   (($slice : expr)[$index: expr]) => (
       fast!(($slice.slice())[$index])
   );
   (($slice : expr)[$index: expr;]) => (
       fast!(($slice.slice())[$index;])
   );
   (($slice : expr)[$start :expr; $end: expr]) => (
       fast!(($slice.slice())[$start;$end])
   );
}
/*
macro_rules! fast_slice_ref {
   (($slice : expr)[$index: expr]) => (
       fast_ref!(($slice.slice())[$index])
   );
   (($slice : expr)[$index: expr]) => (
       fast_ref!(($slice.slice())[$index])
   );
}
*/
macro_rules! fast_slice_mut {
   (($slice : expr)[$index: expr]) => (
       fast_mut!(($slice.slice_mut())[$index])
   );
   (($slice : expr)[$index: expr;]) => (
       fast_mut!(($slice.slice_mut())[$index;])
   );
   (($slice : expr)[$start :expr;$end: expr]) => (
       fast_mut!(($slice.slice_mut())[$start;$end])
   );
}

#[cfg(feature="unsafe")]
macro_rules! fast_mut {
   (($slice : expr)[$index: expr]) => (
       *unsafe{$slice.get_unchecked_mut($index)}
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       unsafe{::core::slice::from_raw_parts_mut(($slice).as_mut_ptr().offset($start as isize), $end - $start)};
   );
   (($slice : expr)[$start: expr ;]) => (
       unsafe{::core::slice::from_raw_parts_mut(($slice).as_mut_ptr().offset($start as isize), $slice.len() - $start)};
   );
   (($slice : expr)[; $end]) => (
       unsafe{::core::slice::from_raw_parts_mut(($slice).as_mut_ptr(), $slice.len())};
   );
}
#[cfg(feature="unsafe")]
macro_rules! fast_uninitialized {
    ($size : expr ) => (unsafe{::core::mem::uninitialized()});
    ($def_value : expr ; $size : expr ) => (unsafe{::core::mem::uninitialized()});
}

/*
pub fn indexk<T>(item : &[T], index : usize) -> &T {
//   return &item[index];
   return unsafe{item.get_unchecked(index)};
}

pub fn indexm<T>(item : &mut [T], index : usize) -> &mut T {
// return &mut item[index]
   return unsafe{item.get_unchecked_mut(index)};
}

pub fn slicek<T>(item : &[T], start : usize, end :usize) -> &[T] {
   return unsafe{slice::from_raw_parts(item.as_ptr().offset(start as isize), end - start)};
}

pub fn slicem<T>(item : &mut [T], start : usize, end :usize) -> &mut [T] {
   return unsafe{slice::from_raw_parts_mut(item.as_mut_ptr().offset(start as isize), end - start)};
}

pub fn slicemend<T>(item : &mut [T], start : usize) -> &mut [T] {
   return unsafe{slice::from_raw_parts_mut(item.as_mut_ptr().offset(start as isize), item.len() - start)};
}
*/
<commit_msg>simplified macros a bit<commit_after>//use core::slice;

#[cfg(not(feature="unsafe"))]
macro_rules! fast_ref {
   (($slice : expr)[$index: expr]) => (
       &($slice)[$index]
   );
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_inner {
   (($slice : expr)[$index: expr]) => (
       ($slice)[$index]
   );
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_inner {
   (($slice : expr)[$index: expr]) => (
       ($slice)[$index]
   );
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast {
   (($slice : expr)[$index: expr]) => (
       ($slice)[$index]
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       &($slice)[$start .. $end]
   );
   (($slice : expr)[$start: expr ;]) => (
       &($slice)[$start .. ]
   );
   (($slice : expr)[; $end]) => (
       &($slice)[.. $end ]
   );
}
#[cfg(not(feature="unsafe"))]
macro_rules! fast_uninitialized {
    [$size : expr] => ([0; $size]);
    [$def_value : expr ; $size : expr] => ([$def_value; $size]);
}

#[cfg(not(feature="unsafe"))]
macro_rules! fast_mut {
   (($slice : expr)[$index: expr]) => (
       ($slice)[$index]
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       &mut $slice[$start..$end]
   );
   (($slice : expr)[$start: expr ;]) => (
       &mut $slice[$start..]
   );
   (($slice : expr)[; $end]) => (
       &mut $slice[..$end]
   );
}

#[cfg(feature="unsafe")]
#[allow(unused_unsafe)]
macro_rules! fast_ref {
   (($slice : expr)[$index: expr]) => (
       unsafe{$slice.get_unchecked($index)}
   );
}

#[cfg(feature="unsafe")]
macro_rules! fast_inner {
   (($slice : expr)[$index: expr]) => (
       *$slice.get_unchecked($index)
   );
}
/*
#[cfg(feature="unsafe")]
macro_rules! fast_slice {
   (($slice : expr)[$index: expr]) => (
       unsafe{*$slice.slice().get_unchecked($index)}
   );
}
*/
#[cfg(feature="unsafe")]
macro_rules! fast {
   (($slice : expr)[$index: expr]) => (
       unsafe{*$slice.get_unchecked($index)}
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       unsafe{::core::slice::from_raw_parts(($slice).as_ptr().offset($start as isize), $end - $start)};
   );
   (($slice : expr)[$start: expr ;]) => (
       unsafe{::core::slice::from_raw_parts(($slice).as_ptr().offset($start as isize), $slice.len() - $start)};
   );
   (($slice : expr)[; $end]) => (
       unsafe{::core::slice::from_raw_parts(($slice).as_ptr(), $slice.len())};
   );
}

macro_rules! fast_slice {
   (($slice : expr)[$index: expr]) => (
       fast!(($slice.slice())[$index])
   );
   (($slice : expr)[$index: expr;]) => (
       fast!(($slice.slice())[$index;])
   );
   (($slice : expr)[$start :expr; $end: expr]) => (
       fast!(($slice.slice())[$start;$end])
   );
}
/*
macro_rules! fast_slice_ref {
   (($slice : expr)[$index: expr]) => (
       fast_ref!(($slice.slice())[$index])
   );
   (($slice : expr)[$index: expr]) => (
       fast_ref!(($slice.slice())[$index])
   );
}
*/
macro_rules! fast_slice_mut {
   (($slice : expr)[$index: expr]) => (
       fast_mut!(($slice.slice_mut())[$index])
   );
   (($slice : expr)[$index: expr;]) => (
       fast_mut!(($slice.slice_mut())[$index;])
   );
   (($slice : expr)[$start :expr;$end: expr]) => (
       fast_mut!(($slice.slice_mut())[$start;$end])
   );
}

#[cfg(feature="unsafe")]
macro_rules! fast_mut {
   (($slice : expr)[$index: expr]) => (
       *unsafe{$slice.get_unchecked_mut($index)}
   );
   (($slice : expr)[$start: expr ; $end : expr]) => (
       unsafe{::core::slice::from_raw_parts_mut(($slice).as_mut_ptr().offset($start as isize), $end - $start)};
   );
   (($slice : expr)[$start: expr ;]) => (
       unsafe{::core::slice::from_raw_parts_mut(($slice).as_mut_ptr().offset($start as isize), $slice.len() - $start)};
   );
   (($slice : expr)[; $end]) => (
       unsafe{::core::slice::from_raw_parts_mut(($slice).as_mut_ptr(), $slice.len())};
   );
}
#[cfg(feature="unsafe")]
macro_rules! fast_uninitialized {
    ($size : expr ) => (unsafe{::core::mem::uninitialized()});
    ($def_value : expr ; $size : expr ) => (unsafe{::core::mem::uninitialized()});
}

/*
pub fn indexk<T>(item : &[T], index : usize) -> &T {
//   return &item[index];
   return unsafe{item.get_unchecked(index)};
}

pub fn indexm<T>(item : &mut [T], index : usize) -> &mut T {
// return &mut item[index]
   return unsafe{item.get_unchecked_mut(index)};
}

pub fn slicek<T>(item : &[T], start : usize, end :usize) -> &[T] {
   return unsafe{slice::from_raw_parts(item.as_ptr().offset(start as isize), end - start)};
}

pub fn slicem<T>(item : &mut [T], start : usize, end :usize) -> &mut [T] {
   return unsafe{slice::from_raw_parts_mut(item.as_mut_ptr().offset(start as isize), end - start)};
}

pub fn slicemend<T>(item : &mut [T], start : usize) -> &mut [T] {
   return unsafe{slice::from_raw_parts_mut(item.as_mut_ptr().offset(start as isize), item.len() - start)};
}
*/
<|endoftext|>


<commit_before>//! # Rope metrics
//!
//! A [`Metric`] represents a measurement with which indices into a [`Rope`]
//! may be calculated.
//!
//! All [`Rope`] methods are optionally parameterised with [`Metric`]s. This
//! means that you can [`split`], [`insert`], or [`delete`] Ropes on character,
//! line, or grapheme indices, without necessitating the addition of a whole
//! bunch of new, wordy method names like `split_on_grapheme_index` and so on.
//!
//! # Examples
//!
//! If I wanted to delete characters 10 to 15 from rope _r_, I could say:
//!
//! ```
//! # use an_rope::Rope;
//! let mut r = Rope::from("this is a long rope");
//! r.delete(10..15);
//! assert_eq!(&r, "this is a rope");
//! ```
//!
//! Suppose my Rope contained some strange Unicode characters, and I realised
//! that I actually wanted to delete _graphemes_ 10 to 12. In that case, I
//! could say:
//!
//! ```
//! # use an_rope::Rope;
//! use an_rope::metric::Grapheme;
//! let mut r = Rope::from("this is a 🆒🆕 rope, 🆗!");
//! r.delete(Grapheme(10)..Grapheme(12));
//! assert_eq!(&r, "this is a rope, 🆗!");
//! ```
//!

use std::convert;
use std::ops::{Add, Sub};
use std::default::Default;
use std::fmt;

/// # The class of monoids
///
/// The class of [monoid]s (types with an accumulative binary operation that has
/// an identity).
///
/// Technically, `Add<Self, Output=Self>` is standing in for "semigroup" here,
/// while [`Default`] is standing in for "identity"[^id].
///
/// An instance _M_ should satisfy the following laws:
///
///  + _x_`.add(`_M_`::default())` = _x_
///  + _M_`::default().add(`_x_`)` = _x_
///  + _x_`.add(`_y_`.add(`_z_`))` = _z_`.add(`_x_`.add(`_y_`))`
///  + _M_`::accumulate(`_a_`)` = _a_`.fold(`_M_`::default,`_M_`::sum)`
///
/// [^id]: A mathematician might point out that it might be more correct to
///        represent the "identity" operation using the [`Zero`] trait rather
///        than [`Default`], as the documentation for `Zero` notes that "[t]his
///        trait is intended for use in conjunction with `Add`, as an identity".
///        However, the `Zero` trait is marked as unstable, so it would only be
///        useable on nightly Rust, and its use is deprecated. Thus, `Default`.
/// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html)
/// [`Zero`]: https://doc.rust-lang.org/std/num/trait.Zero.html
/// [monoid]: http://mathworld.wolfram.com/Monoid.html
pub trait Monoid: Add<Self, Output=Self> + Default + Sized {
    #[inline]
    fn accumulate<F>(xs: F) -> Self
    where F: Iterator<Item=Self>
        , Self: Sized {
        xs.fold(Self::default(), Self::add)
    }
}

/// Trait indicating that a type may be measured with [`Metric`] _M_.
///
///
/// [`Metric`]: trait.Metric.html
pub trait Measured<M: Metric> {
    /// Apply `Metric` to `Self`
    ///
    /// Although we aren't currently enforcing this, `measure`ing a `Node` with
    /// two children should produce the same result as `measure`ing both
    /// children and `Monoid::sum`ming the result. That is to say, `measure`
    /// should be a [_monoid homomorphism_].
    ///
    /// [_monoid homomorphism_]:
    /// https://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms
    fn measure(&self) -> M;

    /// Measure the `weight` of `Node` by this `metric`.
    fn measure_weight(&self) -> M;

    /// Convert the `Metric` into a byte index into the given `Node`
    ///
    /// # Returns
    /// - `Some` with the byte index of the beginning of the `n`th  element
    ///    in `node` measured by this `Metric`, if there is an `n`th element
    /// - `None` if there is no `n`th element in `node`
    fn to_byte_index(&self, index: M) -> Option<usize>;
}

/// A [monoid] that can be applied to a type as a measurement.
///
/// [monoid]: trait.Monoid.html
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
                         + Sub<usize, Output=Self>
                         + Sub<Self, Output=Self>
                         + Eq + Ord
                         + Sized
                         + convert::Into<usize>
                         + Copy
                         + fmt::Debug {

    /// Returns whether text may be split into new leaf nodes using this metric.
    fn is_splittable() -> bool;

    /// Returns the byte index of the next element of this metric in `Node`
    #[inline]
    fn next<M: Measured<Self> >(self, node: &M)-> Option<usize> {
        node.to_byte_index(self + 1)
    }

    /// Returns the byte index of the previous element of this metric in `Node`
    #[inline]
    fn back<M: Measured<Self>>(self, node: &M) -> Option<usize> {
        node.to_byte_index(self - 1)
    }

    /// Returns true if index `i` in `node` is a boundary along this `Metric`
    fn is_boundary<M: Measured<Self>>(node: &M, i: usize) -> bool;
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(pub usize);
impl Default for Grapheme {
    #[inline] fn default() -> Self { Grapheme(0) }
}
impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}
impl convert::Into<usize> for Grapheme {
    #[inline] fn into(self) -> usize { self.0 }
}
impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Add<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Grapheme(self.0 + rhs.0) }
}
impl Monoid for Grapheme { }
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}
impl Sub<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: Self) -> Self { Grapheme(self.0 - rhs.0) }
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(pub usize);
impl Default for Line {
    #[inline] fn default() -> Self { Line(0) }
}
impl Add<Line> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Line(self.0 + rhs.0) }
}
impl Sub<Line> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: Self) -> Self { Line(self.0 - rhs.0) }
}
impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl convert::Into<usize> for Line {
    #[inline] fn into(self) -> usize { self.0 }
}
impl Monoid for Line { }
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}

impl Monoid for usize { }
<commit_msg>test(rope metrics): fix incorrect doctest for rope metrics<commit_after>//! # Rope metrics
//!
//! A [`Metric`] represents a measurement with which indices into a [`Rope`]
//! may be calculated.
//!
//! All [`Rope`] methods are optionally parameterised with [`Metric`]s. This
//! means that you can [`split`], [`insert`], or [`delete`] Ropes on character,
//! line, or grapheme indices, without necessitating the addition of a whole
//! bunch of new, wordy method names like `split_on_grapheme_index` and so on.
//!
//! # Examples
//!
//! If I wanted to delete characters 10 to 15 from rope _r_, I could say:
//!
//! ```
//! # use an_rope::Rope;
//! let mut r = Rope::from("this is a long rope");
//! r.delete(10..15);
//! assert_eq!(&r, "this is a rope");
//! ```
//!
//! Suppose my Rope contained some strange Unicode characters, and I realised
//! that I actually wanted to delete _graphemes_ 10 to 13. In that case, I
//! could say:
//!
//! ```
//! # use an_rope::Rope;
//! use an_rope::metric::Grapheme;
//! let mut r = Rope::from("this is a 🆒🆕 rope, 🆗!");
//! r.delete(Grapheme(10)..Grapheme(13));
//! assert_eq!(&r, "this is a rope, 🆗!");
//! ```
//!

use std::convert;
use std::ops::{Add, Sub};
use std::default::Default;
use std::fmt;

/// # The class of monoids
///
/// The class of [monoid]s (types with an accumulative binary operation that has
/// an identity).
///
/// Technically, `Add<Self, Output=Self>` is standing in for "semigroup" here,
/// while [`Default`] is standing in for "identity"[^id].
///
/// An instance _M_ should satisfy the following laws:
///
///  + _x_`.add(`_M_`::default())` = _x_
///  + _M_`::default().add(`_x_`)` = _x_
///  + _x_`.add(`_y_`.add(`_z_`))` = _z_`.add(`_x_`.add(`_y_`))`
///  + _M_`::accumulate(`_a_`)` = _a_`.fold(`_M_`::default,`_M_`::sum)`
///
/// [^id]: A mathematician might point out that it might be more correct to
///        represent the "identity" operation using the [`Zero`] trait rather
///        than [`Default`], as the documentation for `Zero` notes that "[t]his
///        trait is intended for use in conjunction with `Add`, as an identity".
///        However, the `Zero` trait is marked as unstable, so it would only be
///        useable on nightly Rust, and its use is deprecated. Thus, `Default`.
/// [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html)
/// [`Zero`]: https://doc.rust-lang.org/std/num/trait.Zero.html
/// [monoid]: http://mathworld.wolfram.com/Monoid.html
pub trait Monoid: Add<Self, Output=Self> + Default + Sized {
    #[inline]
    fn accumulate<F>(xs: F) -> Self
    where F: Iterator<Item=Self>
        , Self: Sized {
        xs.fold(Self::default(), Self::add)
    }
}

/// Trait indicating that a type may be measured with [`Metric`] _M_.
///
///
/// [`Metric`]: trait.Metric.html
pub trait Measured<M: Metric> {
    /// Apply `Metric` to `Self`
    ///
    /// Although we aren't currently enforcing this, `measure`ing a `Node` with
    /// two children should produce the same result as `measure`ing both
    /// children and `Monoid::sum`ming the result. That is to say, `measure`
    /// should be a [_monoid homomorphism_].
    ///
    /// [_monoid homomorphism_]:
    /// https://en.wikipedia.org/wiki/Monoid#Monoid_homomorphisms
    fn measure(&self) -> M;

    /// Measure the `weight` of `Node` by this `metric`.
    fn measure_weight(&self) -> M;

    /// Convert the `Metric` into a byte index into the given `Node`
    ///
    /// # Returns
    /// - `Some` with the byte index of the beginning of the `n`th  element
    ///    in `node` measured by this `Metric`, if there is an `n`th element
    /// - `None` if there is no `n`th element in `node`
    fn to_byte_index(&self, index: M) -> Option<usize>;
}

/// A [monoid] that can be applied to a type as a measurement.
///
/// [monoid]: trait.Monoid.html
pub trait Metric: Monoid + Eq + Add<usize, Output=Self>
                         + Sub<usize, Output=Self>
                         + Sub<Self, Output=Self>
                         + Eq + Ord
                         + Sized
                         + convert::Into<usize>
                         + Copy
                         + fmt::Debug {

    /// Returns whether text may be split into new leaf nodes using this metric.
    fn is_splittable() -> bool;

    /// Returns the byte index of the next element of this metric in `Node`
    #[inline]
    fn next<M: Measured<Self> >(self, node: &M)-> Option<usize> {
        node.to_byte_index(self + 1)
    }

    /// Returns the byte index of the previous element of this metric in `Node`
    #[inline]
    fn back<M: Measured<Self>>(self, node: &M) -> Option<usize> {
        node.to_byte_index(self - 1)
    }

    /// Returns true if index `i` in `node` is a boundary along this `Metric`
    fn is_boundary<M: Measured<Self>>(node: &M, i: usize) -> bool;
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(pub usize);
impl Default for Grapheme {
    #[inline] fn default() -> Self { Grapheme(0) }
}
impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}
impl convert::Into<usize> for Grapheme {
    #[inline] fn into(self) -> usize { self.0 }
}
impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Add<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Grapheme(self.0 + rhs.0) }
}
impl Monoid for Grapheme { }
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}
impl Sub<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: Self) -> Self { Grapheme(self.0 - rhs.0) }
}

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(pub usize);
impl Default for Line {
    #[inline] fn default() -> Self { Line(0) }
}
impl Add<Line> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Line(self.0 + rhs.0) }
}
impl Sub<Line> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: Self) -> Self { Line(self.0 - rhs.0) }
}
impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl convert::Into<usize> for Line {
    #[inline] fn into(self) -> usize { self.0 }
}
impl Monoid for Line { }
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}

impl Monoid for usize { }
<|endoftext|>


<commit_before>use std::io::net::ip::{Port, IpAddr};

use http::method;

use router::Router;
use middleware::{ MiddlewareStack, Middleware };
use server::Server;
use request::Request;
use response::Response;

//pre defined middleware
use static_files_handler::StaticFilesHandler;
use json_body_parser::JsonBodyParser;

///Nickel is the application object. It's the surface that
///holds all public APIs.

#[deriving(Clone)]
pub struct Nickel{
    router: Router,
    middleware_stack: MiddlewareStack,
    server: Option<Server>
}
impl Nickel {

    /// In order to use Nickels API one first has to create an instance.
    ///
    /// # Example
    /// ```rust
    /// let mut server = Nickel::new();
    /// ```
    pub fn new() -> Nickel {
        let router = Router::new();
        let middleware_stack = MiddlewareStack::new();
        Nickel {
            router: router,
            middleware_stack: middleware_stack,
            server: None,
        }
    }

    /// Registers a handler to be used for a specific GET request.
    /// Handlers are assigned to paths and paths are allowed to contain
    /// variables and wildcards.
    ///
    /// # Example without variables and wildcards
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches /user");
    /// };
    /// server.get("/user", handler);
    /// ```
    /// # Example with variables
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     let text = format!("This is user: {}", request.params.get(&"userid".to_string()));
    ///     response.send(text.as_slice());
    /// };
    /// server.get("/user/:userid", handler);
    /// ```
    /// # Example with simple wildcard
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 but not /user/extended/list/4711");
    /// };
    /// server.get("/user/*/:userid", handler);
    /// ```
    /// # Example with double wildcard
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 and also /user/extended/list/4711");
    /// };
    /// server.get("/user/**/:userid", handler);
    /// ```
    pub fn get(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Get, String::from_str(uri), handler);
    }

    /// Registers a handler to be used for a specific POST request.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/post/request");
    /// };
    /// server.post("/a/post/request", handler);
    /// ```
    /// Take a look at `get()` for a more detailed description.
    pub fn post(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Post, String::from_str(uri), handler);
    }

    /// Registers a handler to be used for a specific PUT request.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/put/request");
    /// };
    /// server.put("/a/put/request", handler);
    /// ```
    /// Take a look at `get(..)` for a more detailed description.
    pub fn put(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Put, String::from_str(uri), handler);
    }

    /// Registers a handler to be used for a specific DELETE request.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches a DELETE request to /a/delete/request");
    /// };
    /// server.delete("/a/delete/request", handler);
    /// ```
    /// Take a look at `get(...)` for a more detailed description.
    pub fn delete(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Put, String::from_str(uri), handler);
    }

    /// Registers a middleware handler which will be invoked among other middleware
    /// handlers before each request. Middleware can be stacked and is invoked in the
    /// same order it was registered.
    ///
    /// A middleware handler is nearly identical to a regular route handler with the only
    /// difference that it expects a return value of boolean. That is to indicate whether
    /// other middleware handler (if any) further down the stack should continue or if the
    /// middleware invocation should be stopped after the current handler.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn logger (req: &Request, res: &mut Response) -> bool{
    ///     println!("logging request: {}", req.origin.request_uri);
    ///     true
    /// }
    /// ```
    pub fn utilize<T: Middleware>(&mut self, handler: T){
        self.middleware_stack.add(handler);
    }

    /// Create a new middleware to serve files from within a given root directory.
    /// The file to serve will be determined by combining the requested Url with
    /// the provided root directory.
    ///
    ///
    /// # Example
    /// ```rust
    /// let mut server = Nickel::new();
    /// server.utilize(Nickel::static_files("/path/to/serve/"));
    /// ```
    pub fn static_files(root_path: &str) -> StaticFilesHandler {
        StaticFilesHandler::new(root_path)
    }

    /// Create a new middleware to parse JSON bodies.
    ///
    ///
    /// # Example
    /// ```rust
    ///
    /// #[deriving(Decodable, Encodable)]
    /// pub struct Person {
    ///     pub firstname: String,
    ///     pub lastname:  String,
    /// }
    ///
    /// let mut server = Nickel::new();
    /// server.utilize(Nickel::json_body_parser();
    ///
    /// fn post_handler (request: &Request, response: &mut Response) {
    ///
    ///     let person = request.json_as::<Person>().unwrap();
    ///     let text = format!("Hello {} {}", person.firstname, person.lastname);
    ///     response.send(text.as_slice());
    /// };
    ///
    /// server.post("/a/post/request", post_handler);
    /// ```
    pub fn json_body_parser() -> JsonBodyParser {
        JsonBodyParser
    }

    /// Bind and listen for connections on the given host and port
    ///
    /// # Example
    /// ```rust
    /// let mut server = Nickel::new();
    /// server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
    /// ```
    pub fn listen(mut self, ip: IpAddr, port: Port) {
        self.server = Some(Server::new(self.router, self.middleware_stack, ip, port));
        self.server.unwrap().serve();
    }
}
<commit_msg>refactor(docs): remove unneccesary pub<commit_after>use std::io::net::ip::{Port, IpAddr};

use http::method;

use router::Router;
use middleware::{ MiddlewareStack, Middleware };
use server::Server;
use request::Request;
use response::Response;

//pre defined middleware
use static_files_handler::StaticFilesHandler;
use json_body_parser::JsonBodyParser;

///Nickel is the application object. It's the surface that
///holds all public APIs.

#[deriving(Clone)]
pub struct Nickel{
    router: Router,
    middleware_stack: MiddlewareStack,
    server: Option<Server>
}
impl Nickel {

    /// In order to use Nickels API one first has to create an instance.
    ///
    /// # Example
    /// ```rust
    /// let mut server = Nickel::new();
    /// ```
    pub fn new() -> Nickel {
        let router = Router::new();
        let middleware_stack = MiddlewareStack::new();
        Nickel {
            router: router,
            middleware_stack: middleware_stack,
            server: None,
        }
    }

    /// Registers a handler to be used for a specific GET request.
    /// Handlers are assigned to paths and paths are allowed to contain
    /// variables and wildcards.
    ///
    /// # Example without variables and wildcards
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches /user");
    /// };
    /// server.get("/user", handler);
    /// ```
    /// # Example with variables
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     let text = format!("This is user: {}", request.params.get(&"userid".to_string()));
    ///     response.send(text.as_slice());
    /// };
    /// server.get("/user/:userid", handler);
    /// ```
    /// # Example with simple wildcard
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 but not /user/extended/list/4711");
    /// };
    /// server.get("/user/*/:userid", handler);
    /// ```
    /// # Example with double wildcard
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches /user/list/4711 and also /user/extended/list/4711");
    /// };
    /// server.get("/user/**/:userid", handler);
    /// ```
    pub fn get(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Get, String::from_str(uri), handler);
    }

    /// Registers a handler to be used for a specific POST request.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/post/request");
    /// };
    /// server.post("/a/post/request", handler);
    /// ```
    /// Take a look at `get()` for a more detailed description.
    pub fn post(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Post, String::from_str(uri), handler);
    }

    /// Registers a handler to be used for a specific PUT request.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches a POST request to /a/put/request");
    /// };
    /// server.put("/a/put/request", handler);
    /// ```
    /// Take a look at `get(..)` for a more detailed description.
    pub fn put(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Put, String::from_str(uri), handler);
    }

    /// Registers a handler to be used for a specific DELETE request.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn handler (request: Request, response: &mut Response) {
    ///     response.send("This matches a DELETE request to /a/delete/request");
    /// };
    /// server.delete("/a/delete/request", handler);
    /// ```
    /// Take a look at `get(...)` for a more detailed description.
    pub fn delete(&mut self, uri: &str, handler: fn(request: &Request, response: &mut Response)){
        self.router.add_route(method::Put, String::from_str(uri), handler);
    }

    /// Registers a middleware handler which will be invoked among other middleware
    /// handlers before each request. Middleware can be stacked and is invoked in the
    /// same order it was registered.
    ///
    /// A middleware handler is nearly identical to a regular route handler with the only
    /// difference that it expects a return value of boolean. That is to indicate whether
    /// other middleware handler (if any) further down the stack should continue or if the
    /// middleware invocation should be stopped after the current handler.
    ///
    /// # Example
    ///
    /// ```rust
    /// fn logger (req: &Request, res: &mut Response) -> bool{
    ///     println!("logging request: {}", req.origin.request_uri);
    ///     true
    /// }
    /// ```
    pub fn utilize<T: Middleware>(&mut self, handler: T){
        self.middleware_stack.add(handler);
    }

    /// Create a new middleware to serve files from within a given root directory.
    /// The file to serve will be determined by combining the requested Url with
    /// the provided root directory.
    ///
    ///
    /// # Example
    /// ```rust
    /// let mut server = Nickel::new();
    /// server.utilize(Nickel::static_files("/path/to/serve/"));
    /// ```
    pub fn static_files(root_path: &str) -> StaticFilesHandler {
        StaticFilesHandler::new(root_path)
    }

    /// Create a new middleware to parse JSON bodies.
    ///
    ///
    /// # Example
    /// ```rust
    ///
    /// #[deriving(Decodable, Encodable)]
    /// struct Person {
    ///     firstname: String,
    ///     lastname:  String,
    /// }
    ///
    /// let mut server = Nickel::new();
    /// server.utilize(Nickel::json_body_parser();
    ///
    /// fn post_handler (request: &Request, response: &mut Response) {
    ///
    ///     let person = request.json_as::<Person>().unwrap();
    ///     let text = format!("Hello {} {}", person.firstname, person.lastname);
    ///     response.send(text.as_slice());
    /// };
    ///
    /// server.post("/a/post/request", post_handler);
    /// ```
    pub fn json_body_parser() -> JsonBodyParser {
        JsonBodyParser
    }

    /// Bind and listen for connections on the given host and port
    ///
    /// # Example
    /// ```rust
    /// let mut server = Nickel::new();
    /// server.listen(Ipv4Addr(127, 0, 0, 1), 6767);
    /// ```
    pub fn listen(mut self, ip: IpAddr, port: Port) {
        self.server = Some(Server::new(self.router, self.middleware_stack, ip, port));
        self.server.unwrap().serve();
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::mem;
use std::str;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};

use super::{Catalog, Message};

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

fn from_utf8(bytes: &[u8]) -> Result<&str, Error> {
    str::from_utf8(bytes).map_err(|_| DecodingError)
}

fn parse_catalog<R: io::Read>(mut file: R) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    for _ in 0..num_strings {
        let id;
        let context;
        let translated: Vec<&str>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            if n < off + len {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(from_utf8(ctx)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(from_utf8(b)),
                None => return Err(Eof),
            };
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            if n < off + len {
                return Err(Eof);
            }
            let decode_results = (&contents[off..off + len])
                                     .split(|x| *x == 0)
                                     .map(from_utf8)
                                     .collect::<Vec<_>>();
            if decode_results.iter().any(|r| r.is_err()) {
                return Err(DecodingError);
            }
            translated = decode_results.into_iter().map(|r| r.unwrap()).collect();
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff: &[u8] = &[0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff);
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff);
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff);
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff);
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let mut reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let mut reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let mut reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<commit_msg>Compatibility with Rust 1.1<commit_after>extern crate byteorder;

use std::error;
use std::fmt;
use std::io;
use std::mem;
use std::str;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};

use super::{Catalog, Message};

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

fn from_utf8(bytes: &[u8]) -> Result<&str, Error> {
    str::from_utf8(bytes).map_err(|_| DecodingError)
}

fn parse_catalog<R: io::Read>(mut file: R) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    for _ in 0..num_strings {
        let id;
        let context;
        let translated: Vec<&str>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            if n < off + len {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(from_utf8(ctx)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(from_utf8(b)),
                None => return Err(Eof),
            };
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            if n < off + len {
                return Err(Eof);
            }
            let decode_results = (&contents[off..off + len])
                                     .split(|x| *x == 0)
                                     .map(from_utf8)
                                     .collect::<Vec<_>>();
            if decode_results.iter().any(|r| r.is_err()) {
                return Err(DecodingError);
            }
            translated = decode_results.into_iter().map(|r| r.unwrap()).collect();
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..]).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..]).is_ok());
    }

    {
        let mut reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let mut reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let mut reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<|endoftext|>