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

pub fn trim_current_dir_prefix<S: AsRef<str>>(path_name: S) -> String {
    let pattern = format!(".{}", MAIN_SEPARATOR);

    path_name
        .as_ref()
        .trim_left_matches(&pattern)
        .to_string()
}

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

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

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(trim_current_dir_prefix))
        .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();
        }

        fn to_string_forcely(path: PathBuf) -> String {
            path.to_str().unwrap().to_string()
        }
    }

    #[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 trim_current_dir_prefix_should_return_trimmed() {
        let path_names = [
            (""   , "./"    ),
            (""   , "././"  ),
            (""   , "./././"),
            ("a"  , "./a"   ),
            ("a/" , "./a/"  ),
            ("a/b", "./a/b" ),
        ];
        for &(correct, input) in &path_names {
            assert_eq!(correct.to_string(), trim_current_dir_prefix(input));
        }
    }
    #[test]
    fn trim_current_dir_prefix_should_return_as_it_is() {
        let path_names = [
            "",
            "/",
            "/a",
            "/a/b",
            "a",
            "a/",
            "a/b",
        ];
        for path_name in &path_names {
            assert_eq!(path_name.to_string(), trim_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();
        correct.insert(Helper::to_string_forcely(helper.path_to_f1()));
        correct.insert(Helper::to_string_forcely(helper.path_to_f2()));
        correct.insert(Helper::to_string_forcely(helper.path_to_f3()));

        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());
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        fs::remove_file(helper.path_to_f3()).ok();
        correct.insert(helper.path_to_d3());
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        fs::remove_file(helper.path_to_f2()).ok();
        correct.insert(helper.path_to_d2());
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        fs::remove_file(helper.path_to_f4()).ok();
        correct.insert(helper.path_to_d5());
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        helper.remove_dirs_and_files();
    }
}
<commit_msg>[Test] Enhance test of potentially_empty_dirs()<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
    });
}

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 trim_current_dir_prefix<S: AsRef<str>>(path_name: S) -> String {
    let pattern = format!(".{}", MAIN_SEPARATOR);

    path_name
        .as_ref()
        .trim_left_matches(&pattern)
        .to_string()
}

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

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

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(trim_current_dir_prefix))
        .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();
        }

        fn to_string_forcely(path: PathBuf) -> String {
            path.to_str().unwrap().to_string()
        }
    }

    #[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 trim_current_dir_prefix_should_return_trimmed() {
        let path_names = [
            (""   , "./"    ),
            (""   , "././"  ),
            (""   , "./././"),
            ("a"  , "./a"   ),
            ("a/" , "./a/"  ),
            ("a/b", "./a/b" ),
        ];
        for &(correct, input) in &path_names {
            assert_eq!(correct.to_string(), trim_current_dir_prefix(input));
        }
    }
    #[test]
    fn trim_current_dir_prefix_should_return_as_it_is() {
        let path_names = [
            "",
            "/",
            "/a",
            "/a/b",
            "a",
            "a/",
            "a/b",
        ];
        for path_name in &path_names {
            assert_eq!(path_name.to_string(), trim_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();
        correct.insert(Helper::to_string_forcely(helper.path_to_f1()));
        correct.insert(Helper::to_string_forcely(helper.path_to_f2()));
        correct.insert(Helper::to_string_forcely(helper.path_to_f3()));

        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());
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        correct.insert(helper.path_to_d3());
        assert_eq!(correct, potentially_empty_dirs(&root, vec![helper.path_to_f3()]));
        fs::remove_file(helper.path_to_f3()).ok();
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        correct.insert(helper.path_to_d2());
        assert_eq!(correct, potentially_empty_dirs(&root, vec![helper.path_to_f2()]));
        fs::remove_file(helper.path_to_f2()).ok();
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

        correct.insert(helper.path_to_d5());
        assert_eq!(correct, potentially_empty_dirs(&root, vec![helper.path_to_f4()]));
        fs::remove_file(helper.path_to_f4()).ok();
        assert_eq!(correct, potentially_empty_dirs(&root, Vec::new()));

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


<commit_before>extern crate libc;

use std::io::Read;
use std::io::Result;
use std::ptr;
use super::liblz4::*;

use self::libc::size_t;

const BUFFER_SIZE: usize = 32 * 1024;

struct DecoderContext {
	c: LZ4FDecompressionContext,
}

pub struct Decoder<R> {
	c: DecoderContext,
	r: R,
	buf: [u8; BUFFER_SIZE],
	pos: usize,
	len: usize,
	eof: bool,
}

impl<R: Read> Decoder<R> {
	/// Creates a new encoder which will have its output written to the given
	/// output stream. The output stream can be re-acquired by calling
	/// `finish()`
	pub fn new(r: R) -> Result<Decoder<R>> {
		Ok (Decoder {
			r: r,
			c: try! (DecoderContext::new()),
			buf: [0; BUFFER_SIZE],
			pos: BUFFER_SIZE,
			len: BUFFER_SIZE,
			eof: false,
		})
	}
}

impl<R: Read> Read for Decoder<R> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize>
	{
		if self.eof
		{
			return Ok(0);
		}
		let mut dst_offset: usize = 0;
		while dst_offset < buf.len()
		{
			if self.pos >= self.len
			{
				self.pos = 0;
				self.len = try! (self.r.read(&mut self.buf));
				if self.len <= 0
				{
					break;
				}
			}
			while (dst_offset < buf.len()) && (self.pos < self.len)
			{
				let mut src_size = (self.len - self.pos) as size_t;
				let mut dst_size = (buf.len() - dst_offset) as size_t;
				let len = try! (check_error(unsafe {LZ4F_decompress(self.c.c, buf[dst_offset..].as_mut_ptr(), &mut dst_size, self.buf[self.pos..].as_ptr(), &mut src_size, ptr::null())}));
				self.pos += src_size as usize;
				dst_offset += dst_size as usize;
				if len == 0 {
					self.eof = true;
					return Ok(dst_offset);
				}
			}
		}
		Ok(dst_offset)
	}
}

impl DecoderContext {
	fn new() -> Result<DecoderContext>
	{
		let mut context: LZ4FDecompressionContext = ptr::null_mut();
		try! (check_error(unsafe {
			LZ4F_createDecompressionContext(&mut context, LZ4F_VERSION)
		}));
		Ok(DecoderContext {
			c: context
		})
	}
}

impl Drop for DecoderContext {
	fn drop(&mut self) {
		unsafe
		{
			LZ4F_freeDecompressionContext(self.c)
		};
	}
}

#[cfg(test)]
mod test {
	use std::io::{Cursor, Read, Write};
	use super::super::encoder::EncoderBuilder;
	use super::Decoder;

	const BUFFER_SIZE: usize = 64 * 1024;

	#[test]
	fn test_decoder_smoke() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let expected = b"Some data";
		encoder.write(&expected[..4]).unwrap();
		encoder.write(&expected[4..]).unwrap();
		let (buffer, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(buffer)).unwrap();
		let mut actual = [0; BUFFER_SIZE];

		let size = decoder.read(&mut actual).unwrap();
		assert_eq!(expected, &actual[0..size]);
	}

	#[test]
	fn test_decoder_random() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let mut expected = Vec::new();
		let mut rnd: u32 = 42;
		for _ in 0..1027 * 1023 * 7 {
			expected.push((rnd & 0xFF) as u8);
			rnd = ((1664525 as u64) * (rnd as u64) + (1013904223 as u64)) as u32;
		}
		encoder.write(&expected).unwrap();
		let (encoded, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(encoded)).unwrap();
		let mut actual = Vec::new();
		loop {
			let mut buffer = [0; BUFFER_SIZE];
			let size = decoder.read(&mut buffer).unwrap();
			if size == 0 {
				break;
			}
			actual.write(&buffer[0..size]).unwrap();
		}
		assert_eq!(expected, actual);
	}
}
<commit_msg>Don't try to fill up the entire buffer on a read.<commit_after>extern crate libc;

use std::io::Read;
use std::io::Result;
use std::ptr;
use super::liblz4::*;

use self::libc::size_t;

const BUFFER_SIZE: usize = 32 * 1024;

struct DecoderContext {
	c: LZ4FDecompressionContext,
}

pub struct Decoder<R> {
	c: DecoderContext,
	r: R,
	buf: [u8; BUFFER_SIZE],
	pos: usize,
	len: usize,
	eof: bool,
}

impl<R: Read> Decoder<R> {
	/// Creates a new encoder which will have its output written to the given
	/// output stream. The output stream can be re-acquired by calling
	/// `finish()`
	pub fn new(r: R) -> Result<Decoder<R>> {
		Ok (Decoder {
			r: r,
			c: try! (DecoderContext::new()),
			buf: [0; BUFFER_SIZE],
			pos: BUFFER_SIZE,
			len: BUFFER_SIZE,
			eof: false,
		})
	}
}

impl<R: Read> Read for Decoder<R> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize>
	{
		if self.eof || buf.len() == 0
		{
			return Ok(0);
		}
		let mut dst_offset: usize = 0;
		while dst_offset == 0
		{
			if self.pos >= self.len
			{
				self.pos = 0;
				self.len = try! (self.r.read(&mut self.buf));
				if self.len <= 0
				{
					break;
				}
			}
			while (dst_offset < buf.len()) && (self.pos < self.len)
			{
				let mut src_size = (self.len - self.pos) as size_t;
				let mut dst_size = (buf.len() - dst_offset) as size_t;
				let len = try! (check_error(unsafe {LZ4F_decompress(self.c.c, buf[dst_offset..].as_mut_ptr(), &mut dst_size, self.buf[self.pos..].as_ptr(), &mut src_size, ptr::null())}));
				self.pos += src_size as usize;
				dst_offset += dst_size as usize;
				if len == 0 {
					self.eof = true;
					return Ok(dst_offset);
				}
			}
		}
		Ok(dst_offset)
	}
}

impl DecoderContext {
	fn new() -> Result<DecoderContext>
	{
		let mut context: LZ4FDecompressionContext = ptr::null_mut();
		try! (check_error(unsafe {
			LZ4F_createDecompressionContext(&mut context, LZ4F_VERSION)
		}));
		Ok(DecoderContext {
			c: context
		})
	}
}

impl Drop for DecoderContext {
	fn drop(&mut self) {
		unsafe
		{
			LZ4F_freeDecompressionContext(self.c)
		};
	}
}

#[cfg(test)]
mod test {
	use std::io::{Cursor, Read, Write};
	use super::super::encoder::EncoderBuilder;
	use super::Decoder;

	const BUFFER_SIZE: usize = 64 * 1024;

	#[test]
	fn test_decoder_smoke() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let expected = b"Some data";
		encoder.write(&expected[..4]).unwrap();
		encoder.write(&expected[4..]).unwrap();
		let (buffer, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(buffer)).unwrap();
		let mut actual = [0; BUFFER_SIZE];

		let size = decoder.read(&mut actual).unwrap();
		assert_eq!(expected, &actual[0..size]);
	}

	#[test]
	fn test_decoder_random() {
		let mut encoder = EncoderBuilder::new().level(1).build(Vec::new()).unwrap();
		let mut expected = Vec::new();
		let mut rnd: u32 = 42;
		for _ in 0..1027 * 1023 * 7 {
			expected.push((rnd & 0xFF) as u8);
			rnd = ((1664525 as u64) * (rnd as u64) + (1013904223 as u64)) as u32;
		}
		encoder.write(&expected).unwrap();
		let (encoded, result) = encoder.finish();
		result.unwrap();

		let mut decoder = Decoder::new(Cursor::new(encoded)).unwrap();
		let mut actual = Vec::new();
		loop {
			let mut buffer = [0; BUFFER_SIZE];
			let size = decoder.read(&mut buffer).unwrap();
			if size == 0 {
				break;
			}
			actual.write(&buffer[0..size]).unwrap();
		}
		assert_eq!(expected, actual);
	}
}
<|endoftext|>


<commit_before>#![feature(never_type)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

async fn add(x: u32, y: u32) -> u32 {
    let a = async { x + y };
    a.await
}

async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let x = (add(a, b).await, add(c, d).await);
    x.0 + x.1
}

enum Never {}
fn never() -> Never {
    panic!()
}

async fn includes_never(crash: bool, x: u32) -> u32 {
    let mut result = async { x * x }.await;
    if !crash {
        return result;
    }
    #[allow(unused)]
    let bad = never();
    result *= async { x + x }.await;
    drop(bad);
    result
}

async fn partial_init(x: u32) -> u32 {
    #[allow(unreachable_code)]
    let _x: (String, !) = (String::new(), return async { x + x }.await);
}

fn run_fut(mut fut: impl Future<Output=u32>, output: u32) {
    fn raw_waker_clone(_this: *const ()) -> RawWaker {
        panic!("unimplemented");
    }
    fn raw_waker_wake(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_wake_by_ref(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_drop(_this: *const ()) {}

    static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
        raw_waker_clone,
        raw_waker_wake,
        raw_waker_wake_by_ref,
        raw_waker_drop,
    );

    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output));
}

fn main() {
    let x = 5;
    run_fut(foo(&x, 7), 31);

    run_fut(build_aggregate(1, 2, 3, 4), 10);

    run_fut(includes_never(false, 4), 16);

    run_fut(partial_init(4), 8);
}
<commit_msg>use Wake trait for async-fn driver<commit_after>#![feature(never_type)]
#![feature(wake_trait)]

use std::{future::Future, pin::Pin, task::Poll};
use std::task::{Wake, Waker, Context};
use std::sync::Arc;

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

async fn add(x: u32, y: u32) -> u32 {
    let a = async { x + y };
    a.await
}

async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let x = (add(a, b).await, add(c, d).await);
    x.0 + x.1
}

enum Never {}
fn never() -> Never {
    panic!()
}

async fn includes_never(crash: bool, x: u32) -> u32 {
    let mut result = async { x * x }.await;
    if !crash {
        return result;
    }
    #[allow(unused)]
    let bad = never();
    result *= async { x + x }.await;
    drop(bad);
    result
}

async fn partial_init(x: u32) -> u32 {
    #[allow(unreachable_code)]
    let _x: (String, !) = (String::new(), return async { x + x }.await);
}

fn run_fut(mut fut: impl Future<Output=u32>, output: u32) {
    struct MyWaker;
    impl Wake for MyWaker {
        fn wake(self: Arc<Self>) {
            unimplemented!()
        }
    }

    let waker = Waker::from(Arc::new(MyWaker));
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output));
}

fn main() {
    let x = 5;
    run_fut(foo(&x, 7), 31);

    run_fut(build_aggregate(1, 2, 3, 4), 10);

    run_fut(includes_never(false, 4), 16);

    run_fut(partial_init(4), 8);
}
<|endoftext|>


<commit_before>extern crate log;

use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

struct SimpleLogger;

impl log::Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Debug
    }

    fn log(&self, record: &LogRecord) {
        // if self.enabled(record.metadata()) {
        //     println!("{} - {}", record.level(), record.args());
        // }
        match record.level() {
            LogLevel::Trace => SCLogDebug!(format!("{}",record.args()).as_str()),
            LogLevel::Debug => SCLogDebug!(format!("{}",record.args()).as_str()),
            LogLevel::Info => SCLogInfo!(format!("{}",record.args()).as_str()),
            LogLevel::Warn => SCLogWarning!(format!("{}",record.args()).as_str()),
            LogLevel::Error => SCLogError!(format!("{}",record.args()).as_str()),
        }
    }
}

pub fn init(max_level: LogLevelFilter) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(max_level);
        Box::new(SimpleLogger)
    })
}
<commit_msg>Fix file/line information in logging module<commit_after>extern crate log;

use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

struct SimpleLogger;

impl log::Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Debug
    }

    fn log(&self, record: &LogRecord) {
        // if self.enabled(record.metadata()) {
        //     println!("{} - {}", record.level(), record.args());
        // }
        let file = record.location().file();
        let line = record.location().line();
        match record.level() {
            LogLevel::Trace => SCLogMessage!(10,format!("{}",record.args()).as_str(),file,line),
            LogLevel::Debug => SCLogMessage!(10,format!("{}",record.args()).as_str(),file,line),
            LogLevel::Info  => SCLogMessage!(7, format!("{}",record.args()).as_str(),file,line),
            LogLevel::Warn  => SCLogMessage!(5, format!("{}",record.args()).as_str(),file,line),
            LogLevel::Error => SCLogMessage!(4, format!("{}",record.args()).as_str(),file,line),
        }
    }
}

pub fn init(max_level: LogLevelFilter) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(max_level);
        Box::new(SimpleLogger)
    })
}
<|endoftext|>


<commit_before>//! Functions and data-structures for working with descriptor tables.
use crate::segmentation::SegmentSelector;
use core::fmt;
use core::mem::size_of;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> Default for DescriptorTablePointer<T> {
    fn default() -> DescriptorTablePointer<T> {
        DescriptorTablePointer {
            limit: 0,
            base: core::ptr::null(),
        }
    }
}

impl<T> DescriptorTablePointer<T> {
    pub fn new(tbl: &T) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: tbl as *const T,
            limit: len as u16,
        }
    }

    pub fn new_from_slice(slice: &[T]) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = slice.len() * size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

impl<T> fmt::Debug for DescriptorTablePointer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "DescriptorTablePointer ({} {:?})", { self.limit }, { self.base } )
    }
}

/// Load the GDTR register with the specified base and limit.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn lgdt<T>(gdt: &DescriptorTablePointer<T>) {
    llvm_asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Retrieve base and limit from the GDTR register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn sgdt<T>(idt: &mut DescriptorTablePointer<T>) {
    llvm_asm!("sgdt ($0)" : "+r" (idt as *mut DescriptorTablePointer<T>) :: "memory");
}

/// Loads the segment selector into the selector field of the local
/// descriptor table register (LDTR).
///
/// After the segment selector is loaded in the LDTR,
/// the processor uses the segment selector to locate
/// the segment descriptor for the LDT in the global
/// descriptor table (GDT).
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn load_ldtr(selector: SegmentSelector) {
    llvm_asm!("lldt $0" :: "r" (selector.bits()) : "memory");
}

/// Returns the segment selector from the local descriptor table register (LDTR).
///
/// The returned segment selector points to the segment descriptor
/// (located in the GDT) for the current LDT.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn ldtr() -> SegmentSelector {
    let selector: u16;
    llvm_asm!("sldt $0" : "+r"(selector));
    SegmentSelector::from_raw(selector)
}

/// Load the IDTR register with the specified base and limit.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn lidt<T>(idt: &DescriptorTablePointer<T>) {
    llvm_asm!("lidt ($0)" :: "r" (idt) : "memory");
}

/// Retrieve base and limit from the IDTR register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn sidt<T>(idt: &mut DescriptorTablePointer<T>) {
    llvm_asm!("sidt ($0)" : "+r" (idt as *mut DescriptorTablePointer<T>) :: "memory");
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;

    #[test]
    fn check_sgdt() {
        let gdtr: super::DescriptorTablePointer<u64> = Default::default();
        gdtr.limit = 0xdead;
        gdtr.base = 0xbadc0de as *mut u64;
        unsafe {
            sgdt(&mut gdtr);
        }
        assert_ne!(gdtr.limit, 0);
        assert_ne!(gdtr.base, core::ptr::null_mut());
        assert_ne!(gdtr.limit, 0xdead);
        assert_ne!(gdtr.base, 0xbadc0de);
    }

    #[test]
    fn check_sidt() {
        let gdtr: super::DescriptorTablePointer<u64> = Default::default();
        idtr.limit = 0xdead;
        idtr.base = 0xbadc0de as *mut u64;
        unsafe {
            sidt(&mut idtr);
        }
        assert_ne!(idtr.limit, 0);
        assert_ne!(idtr.base, core::ptr::null_mut());
        assert_ne!(idtr.limit, 0xdead);
        assert_ne!(idtr.base, 0xbadc0de);
    }
}
<commit_msg>Update dtables.rs<commit_after>//! Functions and data-structures for working with descriptor tables.
use crate::segmentation::SegmentSelector;
use core::fmt;
use core::mem::size_of;

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[repr(C, packed)]
pub struct DescriptorTablePointer<Entry> {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: *const Entry,
}

impl<T> Default for DescriptorTablePointer<T> {
    fn default() -> DescriptorTablePointer<T> {
        DescriptorTablePointer {
            limit: 0,
            base: core::ptr::null(),
        }
    }
}

impl<T> DescriptorTablePointer<T> {
    pub fn new(tbl: &T) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: tbl as *const T,
            limit: len as u16,
        }
    }

    pub fn new_from_slice(slice: &[T]) -> Self {
        // GDT, LDT, and IDT all expect the limit to be set to "one less".
        // See Intel 3a, Section 3.5.1 "Segment Descriptor Tables" and
        // Section 6.10 "Interrupt Descriptor Table (IDT)".
        let len = slice.len() * size_of::<T>() - 1;
        assert!(len < 0x10000);
        DescriptorTablePointer {
            base: slice.as_ptr(),
            limit: len as u16,
        }
    }
}

impl<T> fmt::Debug for DescriptorTablePointer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "DescriptorTablePointer ({} {:?})", { self.limit }, { self.base } )
    }
}

/// Load the GDTR register with the specified base and limit.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn lgdt<T>(gdt: &DescriptorTablePointer<T>) {
    llvm_asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Retrieve base and limit from the GDTR register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn sgdt<T>(idt: &mut DescriptorTablePointer<T>) {
    llvm_asm!("sgdt ($0)" : "+r" (idt as *mut DescriptorTablePointer<T>) :: "memory");
}

/// Loads the segment selector into the selector field of the local
/// descriptor table register (LDTR).
///
/// After the segment selector is loaded in the LDTR,
/// the processor uses the segment selector to locate
/// the segment descriptor for the LDT in the global
/// descriptor table (GDT).
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn load_ldtr(selector: SegmentSelector) {
    llvm_asm!("lldt $0" :: "r" (selector.bits()) : "memory");
}

/// Returns the segment selector from the local descriptor table register (LDTR).
///
/// The returned segment selector points to the segment descriptor
/// (located in the GDT) for the current LDT.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn ldtr() -> SegmentSelector {
    let selector: u16;
    llvm_asm!("sldt $0" : "=r"(selector));
    SegmentSelector::from_raw(selector)
}

/// Load the IDTR register with the specified base and limit.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn lidt<T>(idt: &DescriptorTablePointer<T>) {
    llvm_asm!("lidt ($0)" :: "r" (idt) : "memory");
}

/// Retrieve base and limit from the IDTR register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn sidt<T>(idt: &mut DescriptorTablePointer<T>) {
    llvm_asm!("sidt ($0)" : "+r" (idt as *mut DescriptorTablePointer<T>) :: "memory");
}

#[cfg(all(test, feature = "utest"))]
mod test {
    use super::*;

    #[test]
    fn check_sgdt() {
        let gdtr: super::DescriptorTablePointer<u64> = Default::default();
        gdtr.limit = 0xdead;
        gdtr.base = 0xbadc0de as *mut u64;
        unsafe {
            sgdt(&mut gdtr);
        }
        assert_ne!(gdtr.limit, 0);
        assert_ne!(gdtr.base, core::ptr::null_mut());
        assert_ne!(gdtr.limit, 0xdead);
        assert_ne!(gdtr.base, 0xbadc0de);
    }

    #[test]
    fn check_sidt() {
        let gdtr: super::DescriptorTablePointer<u64> = Default::default();
        idtr.limit = 0xdead;
        idtr.base = 0xbadc0de as *mut u64;
        unsafe {
            sidt(&mut idtr);
        }
        assert_ne!(idtr.limit, 0);
        assert_ne!(idtr.base, core::ptr::null_mut());
        assert_ne!(idtr.limit, 0xdead);
        assert_ne!(idtr.base, 0xbadc0de);
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::fmt;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::result::Result;
use std::convert::From;
use std::ascii::AsciiExt;
use rand;
use rand::Rng;
use grid::Grid;
use item::{Item};
use point::{Point};
use tile::{Tile};

// A dungeon level.
pub struct Level {
    depth: u8,
    tiles: Grid<Tile>,
    items: HashMap<Point, Item>,
    visible: HashSet<Point>,
}

pub type Dungeon = [Level; 256];

pub enum MapError {
    ShapeError(usize),    // funny map shape at given line
    TileError(usize, u8), // bad tile (u8) on given map (usize)
    StairError(usize),    // not enough stairs on given map
    IoError(io::Error)
}

impl fmt::Display for MapError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MapError::ShapeError(line) =>
                write!(f, "map error: misshapen map at line {}", line),
            MapError::TileError(whichmap, tile) =>
                write!(f, "map error: unknown tile '{}' on map {}",
                    tile as char, whichmap),
            MapError::StairError(whichmap) =>
                write!(f, "map error: not enough stairs on map {}", whichmap),
            MapError::IoError(ref e) => e.fmt(f)
        }
    }
}

impl From<io::Error> for MapError {
    fn from(e: io::Error) -> Self {
        MapError::IoError(e)
    }
}

// TODO: make early levels easy, handle special case for level 255
pub fn build() -> Result<Vec<Grid<Tile>>, MapError> {
    let mut schemes = read_maps()?;

    // until we have 255 distinct levels, make do with duplicates
    let distinct_schemes = schemes.len();
    while schemes.len() < 255 {
        let which = rand::thread_rng().gen_range(0, distinct_schemes);
        let duplicate = schemes[which].clone();
        schemes.push(duplicate)
    }

    let mut maps: Vec<Grid<Tile>> = Vec::with_capacity(255);
    for (whichmap, scheme) in schemes.iter().enumerate() {
        maps.push(build_map(whichmap, scheme)?)
    }

    rand::thread_rng().shuffle(&mut maps[..]);

    Ok(maps)
}

type Lines<'a> = &'a mut Iterator<Item=io::Result<String>>;

fn read_maps() -> Result<Vec<Grid<u8>>, MapError> {
    let file = File::open("data/maps.txt")?;
    let reader = BufReader::new(file);
    let mut lines = reader.lines();
    let mut maps: Vec<Grid<u8>> = Vec::with_capacity(255);

    let mut linecount: usize = 1;
    loop {
        if lines.next().is_none() {
            return Ok(maps)
        }
        linecount += 1;
        maps.push(read_map(&mut linecount, &mut lines)?);
    }
}

fn read_map(linecount: &mut usize, lines: Lines) -> Result<Grid<u8>, MapError> {
    let mut grid = Grid::empty();
    for _ in 0..13 {
        match lines.next() {
            Some(Ok(ref row)) if row.len() == 19 =>
                grid.grid.extend(row.bytes()),
            Some(Err(e)) => return Err(MapError::IoError(e)),
            _ => return Err(MapError::ShapeError(*linecount))
        }
        *linecount = *linecount + 1
    }

    Ok(grid)
}

fn build_map(whichmap: usize, scheme: &Grid<u8>) -> Result<Grid<Tile>, MapError> {
    let mut map = Grid::empty();

    // preliminary pass: figure out where to place stairs
    let stairtotal = scheme.grid.iter().filter(|&&t| t == b'<').count();
    if stairtotal < 2 {
        return Err(MapError::StairError(whichmap))
    }
    let upstairs = rand::thread_rng().gen_range(0, stairtotal);
    let mut downstairs = upstairs;
    while downstairs == upstairs {
        downstairs = rand::thread_rng().gen_range(0, stairtotal)
    }

    // a HashMap to keep track of which tile (floor or wall) to use for
    // each letter A-Z in the map scheme (and the inverse for a-z)
    let mut tilechoices: HashMap<u8, bool> = HashMap::new();

    let mut staircount = 0;

    for &srctile in scheme.grid.iter() {
        map.grid.push(match srctile {
            b'.' => Tile::Floor,
            b'#' => Tile::Wall,
            b'+' => Tile::Door,
            b'<' => {
                let tile = if staircount == upstairs {
                    Tile::StairsUp
                } else if staircount == downstairs {
                    Tile::StairsDown
                } else {
                    Tile::Floor
                };
                staircount += 1;
                tile
            }
            b'A' ... b'Z' | b'a' ... b'z' => {
                let normalized = srctile.to_ascii_uppercase();
                let selection = *tilechoices.entry(normalized).or_insert_with(||
                    rand::thread_rng().gen() );
                // flip selection for lowercase letters
                // TODO: use srctile.is_ascii_uppercase()
                // once ascii_ctype is stable
                if selection == (srctile == normalized) {
                    Tile::Wall
                } else {
                    Tile::Floor
                }
            }
            _ => return Err(MapError::TileError(whichmap, srctile))
        })
    }

    Ok(map)
}
<commit_msg>flip maps randomly<commit_after>use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::fmt;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::result::Result;
use std::convert::From;
use std::ascii::AsciiExt;
use rand;
use rand::Rng;
use grid;
use grid::Grid;
use item::{Item};
use point::{Point};
use tile::{Tile};

// A dungeon level.
pub struct Level {
    depth: u8,
    tiles: Grid<Tile>,
    items: HashMap<Point, Item>,
    visible: HashSet<Point>,
}

pub type Dungeon = [Level; 256];

pub enum MapError {
    ShapeError(usize),    // funny map shape at given line
    TileError(usize, u8), // bad tile (u8) on given map (usize)
    StairError(usize),    // not enough stairs on given map
    IoError(io::Error)
}

impl fmt::Display for MapError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MapError::ShapeError(line) =>
                write!(f, "map error: misshapen map at line {}", line),
            MapError::TileError(whichmap, tile) =>
                write!(f, "map error: unknown tile '{}' on map {}",
                    tile as char, whichmap),
            MapError::StairError(whichmap) =>
                write!(f, "map error: not enough stairs on map {}", whichmap),
            MapError::IoError(ref e) => e.fmt(f)
        }
    }
}

impl From<io::Error> for MapError {
    fn from(e: io::Error) -> Self {
        MapError::IoError(e)
    }
}

// TODO: make early levels easy, handle special case for level 255
pub fn build() -> Result<Vec<Grid<Tile>>, MapError> {
    let mut schemes = read_maps()?;

    // until we have 255 distinct levels, make do with duplicates
    let distinct_schemes = schemes.len();
    while schemes.len() < 255 {
        let which = rand::thread_rng().gen_range(0, distinct_schemes);
        let duplicate = schemes[which].clone();
        schemes.push(duplicate)
    }

    let mut maps: Vec<Grid<Tile>> = Vec::with_capacity(255);
    for (whichmap, scheme) in schemes.iter().enumerate() {
        let mut map = build_map(whichmap, scheme)?;
        flip_randomly(&mut map);
        maps.push(map)
    }

    rand::thread_rng().shuffle(&mut maps[..]);

    Ok(maps)
}

type Lines<'a> = &'a mut Iterator<Item=io::Result<String>>;

fn read_maps() -> Result<Vec<Grid<u8>>, MapError> {
    let file = File::open("data/maps.txt")?;
    let reader = BufReader::new(file);
    let mut lines = reader.lines();
    let mut maps: Vec<Grid<u8>> = Vec::with_capacity(255);

    let mut linecount: usize = 1;
    loop {
        if lines.next().is_none() {
            return Ok(maps)
        }
        linecount += 1;
        maps.push(read_map(&mut linecount, &mut lines)?);
    }
}

fn read_map(linecount: &mut usize, lines: Lines) -> Result<Grid<u8>, MapError> {
    let mut grid = Grid::empty();
    for _ in 0..13 {
        match lines.next() {
            Some(Ok(ref row)) if row.len() == 19 =>
                grid.grid.extend(row.bytes()),
            Some(Err(e)) => return Err(MapError::IoError(e)),
            _ => return Err(MapError::ShapeError(*linecount))
        }
        *linecount = *linecount + 1
    }

    Ok(grid)
}

fn build_map(whichmap: usize, scheme: &Grid<u8>) -> Result<Grid<Tile>, MapError> {
    let mut map = Grid::empty();

    // preliminary pass: figure out where to place stairs
    let stairtotal = scheme.grid.iter().filter(|&&t| t == b'<').count();
    if stairtotal < 2 {
        return Err(MapError::StairError(whichmap))
    }
    let upstairs = rand::thread_rng().gen_range(0, stairtotal);
    let mut downstairs = upstairs;
    while downstairs == upstairs {
        downstairs = rand::thread_rng().gen_range(0, stairtotal)
    }

    // a HashMap to keep track of which tile (floor or wall) to use for
    // each letter A-Z in the map scheme (and the inverse for a-z)
    let mut tilechoices: HashMap<u8, bool> = HashMap::new();

    let mut staircount = 0;

    for &srctile in scheme.grid.iter() {
        map.grid.push(match srctile {
            b'.' => Tile::Floor,
            b'#' => Tile::Wall,
            b'+' => Tile::Door,
            b'<' => {
                let tile = if staircount == upstairs {
                    Tile::StairsUp
                } else if staircount == downstairs {
                    Tile::StairsDown
                } else {
                    Tile::Floor
                };
                staircount += 1;
                tile
            }
            b'A' ... b'Z' | b'a' ... b'z' => {
                let normalized = srctile.to_ascii_uppercase();
                let selection = *tilechoices.entry(normalized).or_insert_with(||
                    rand::thread_rng().gen() );
                // flip selection for lowercase letters
                // TODO: use srctile.is_ascii_uppercase()
                // once ascii_ctype is stable
                if selection == (srctile == normalized) {
                    Tile::Wall
                } else {
                    Tile::Floor
                }
            }
            _ => return Err(MapError::TileError(whichmap, srctile))
        })
    }

    Ok(map)
}

fn flip_randomly<T>(map: &mut Grid<T>) {
    if rand::thread_rng().gen() {
        // flip horizontally
        for row in map.grid.chunks_mut(grid::WIDTH) {
            row.reverse()
        }
    }
    if rand::thread_rng().gen() {
        // flip both horizontally and vertically
        map.grid.reverse()
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! __perl_xs_len {
    ( $x:expr ) => ( 1 );
    ( $x:expr, $( $xs:expr ),+ ) => ( 1 + __perl_xs_len!($( $xs ),+) );
}

#[macro_export]
macro_rules! xs_return {
    ($ctx:ident, $( $val:expr ),*) => {{
        $ctx.st_prepush();
        $ctx.st_extend(__perl_xs_len!( $( $val ),+ ));
        unsafe {
            $( $ctx.st_push_unsafe($val); )*
        }
        $ctx.st_putback();
        return;
    }}
}

#[macro_export]
macro_rules! XS {
    {
        package $pkg:ident { $( sub $name:ident ($ctx:ident) $body:block )* }
        loader $boot:ident;
    } => {
        $(
            #[allow(non_snake_case)]
            pub extern "C" fn $name (pthx: $crate::raw::PerlContext,
                                     _cv: *mut $crate::raw::CV) {
                let mut $ctx = $crate::Context::new(&pthx);
                $body
            }
        )*

        #[no_mangle]
        #[allow(non_snake_case)]
        pub extern "C" fn $boot (pthx: $crate::raw::PerlContext, _cv: *mut $crate::raw::CV) {
            let mut ctx = $crate::Context::new(&pthx);
            $({
                let fullname = concat!(stringify!($pkg), "::", stringify!($name));
                ctx.new_xs(&fullname, $name);
            })*

            xs_return!(ctx, 1 as $crate::raw::IV);
        }
    }
}
<commit_msg>Add macro to build C-style strings.<commit_after>#[macro_export]
macro_rules! __perl_xs_len {
    ( $x:expr ) => ( 1 );
    ( $x:expr, $( $xs:expr ),+ ) => ( 1 + __perl_xs_len!($( $xs ),+) );
}

#[macro_export]
macro_rules! xs_return {
    ($ctx:ident, $( $val:expr ),*) => {{
        $ctx.st_prepush();
        $ctx.st_extend(__perl_xs_len!( $( $val ),+ ));
        unsafe {
            $( $ctx.st_push_unsafe($val); )*
        }
        $ctx.st_putback();
        return;
    }}
}

#[macro_export]
macro_rules! XS {
    {
        package $pkg:ident { $( sub $name:ident ($ctx:ident) $body:block )* }
        loader $boot:ident;
    } => {
        $(
            #[allow(non_snake_case)]
            pub extern "C" fn $name (pthx: $crate::raw::PerlContext,
                                     _cv: *mut $crate::raw::CV) {
                let mut $ctx = $crate::Context::new(&pthx);
                $body
            }
        )*

        #[no_mangle]
        #[allow(non_snake_case)]
        pub extern "C" fn $boot (pthx: $crate::raw::PerlContext, _cv: *mut $crate::raw::CV) {
            let mut ctx = $crate::Context::new(&pthx);
            $({
                let fullname = concat!(stringify!($pkg), "::", stringify!($name));
                ctx.new_xs(&fullname, $name);
            })*

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

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


<commit_before>// Vector/Point macros
macro_rules! n_pointvector {
    (ops $lhs:ident; $rhs:ident {$($field:ident),*}) => {
        impl<F: Float> ::std::ops::Add<$rhs<F>> for $lhs<F> {
            type Output = $lhs<F>;

            fn add(self, rhs: $rhs<F>) -> $lhs<F> {
                $lhs {
                    $($field: self.$field + rhs.$field),*
                }
            }
        }

        impl<F: Float> ::std::ops::Sub<$rhs<F>> for $lhs<F> {
            type Output = $lhs<F>;

            fn sub(self, rhs: $rhs<F>) -> $lhs<F> {
                $lhs {
                    $($field: self.$field - rhs.$field),*
                }
            }
        }
    };

    (float ops $name:ident {$($field:ident),+}) => {
        impl<F: Float> ::std::ops::Mul<F> for $name<F> {
            type Output = $name<F>;

            fn mul(self, rhs: F) -> $name<F> {
                $name {
                    $($field: self.$field * rhs),+
                }
            }
        }

        impl<F: Float> ::std::ops::Div<F> for $name<F> {
            type Output = $name<F>;

            fn div(self, rhs: F) -> $name<F> {
                $name {
                    $($field: self.$field / rhs),+
                }
            }
        }

        impl<F: Float> ::std::ops::Neg for $name<F> {
            type Output = $name<F>;

            fn neg(self) -> $name<F> {
                $name {
                    $($field: -self.$field),+
                }
            }
        }
    };

    (struct $dims:expr; $name:ident {$($field:ident: $f_ty:ident),+} $sibling:ident) => {
        #[derive(Debug, Clone, Copy)]
        pub struct $name<F: Float> {
            $(pub $field: F),+
        }

        impl<F: Float> $name<F> {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }
        }

        impl<'a, F: Float> ::std::convert::From<&'a [F]> for $name<F> {
            fn from(slice: &'a [F]) -> $name<F> {
                assert_eq!(slice.len(), count!($($field),+));
                let mut index = -1;
                $name{$($field: {
                    index += 1;
                    slice[index as usize]
                }),+}
            }
        }

        impl<F: Float> ::std::convert::Into<[F; $dims]> for $name<F> {
            fn into(self) -> [F; $dims] {
                [$(self.$field),*]
            }
        }

        impl<F: Float> ::std::convert::Into<($($f_ty),*)> for $name<F> {
            fn into(self) -> ($($f_ty),*) {
                ($(self.$field),*)
            }
        }

        impl<F: Float> ::std::convert::From<$sibling<F>> for $name<F> {
            fn from(sib: $sibling<F>) -> $name<F> {
                $name {
                    $($field: sib.$field),*
                }
            }
        }

        n_pointvector!(ops $name; $sibling {$($field),+});
        n_pointvector!(ops $name; $name {$($field),+});
        n_pointvector!(float ops $name {$($field),+});
    };

    ($dims:expr; $p_name:ident, $v_name:ident {$($field:ident),+}) => {
        n_pointvector!(struct $dims; $p_name {$($field: F),+} $v_name);
        n_pointvector!(struct $dims; $v_name {$($field: F),+} $p_name);

        impl<F: Float + FromPrimitive> $v_name<F> {
            pub fn len(self) -> F {
                ($(self.$field.powi(2) +)+ F::from_f32(0.0).unwrap()).sqrt()
            }

            pub fn normalize(self) -> $v_name<F> {
                self / self.len()
            }
        }
    }
}

// Polynomial Macros
macro_rules! count {
    ($idc:tt) => (1);
    ($($element:tt),*) => {{$(count!($element) +)* 0}};
}

macro_rules! n_bezier {
    ($name:ident {
        $($field:ident: $weight:expr),+
    } derived {
        $($dleft:ident - $dright:ident: $dweight:expr),+
    }) => {
        #[derive(Debug, Clone, Copy)]
        pub struct $name<F> where F: ::num::Float + ::num::FromPrimitive {
            $(pub $field: F),+
        }

        impl<F> $name<F> where F: ::num::Float + ::num::FromPrimitive {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }
        }

        impl<F> $crate::traits::BezCurve<F> for $name<F>
                where F: ::num::Float + ::num::FromPrimitive {
            type Point = F;
            type Vector = F;

            fn from_slice(slice: &[F]) -> $name<F> {
                assert!(slice.len() == $name::<F>::order());
                let mut index = -1;
                $name {$($field: {
                    index += 1;
                    slice[index as usize]
                }),+}
            }

            fn interp_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $field =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        self.$field *
                        F::from_i32($weight).unwrap();
                )+
                $($field +)+ F::from_f32(0.0).unwrap()
            }

            fn slope_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($dleft),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $dleft =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        (self.$dleft - self.$dright) *
                        F::from_i32($dweight * (COUNT + 1)).unwrap();
                )+
                $($dleft +)+ F::from_f32(0.0).unwrap()
            }

            #[inline]
            fn order() -> usize {
                count!($($field),+)
            }
        }

        impl<F> ::std::ops::Deref for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            type Target = [F];
            fn deref(&self) -> &[F] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts(self as *const $name<F> as *const F, count!($($field),+))
                }
            }
        }

        impl<F> ::std::ops::DerefMut for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            fn deref_mut(&mut self) -> &mut [F] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts_mut(self as *mut $name<F> as *mut F, count!($($field),+))
                }
            }
        }
    }
}

macro_rules! bez_composite {
    ($name:ident<$poly:ident> {
        $($field:ident: $($n_field:ident),+;)+
    } -> <$point:ident; $vector:ident>;
        $($dim:ident = $($dfield:ident),+;)+) =>
    {
        #[derive(Debug, Clone, Copy)]
        pub struct $name<F: ::num::Float + ::num::FromPrimitive> {
            $(pub $field: $point<F>),+
        }

        impl<F: ::num::Float + ::num::FromPrimitive> $name<F> {
            pub fn new($($($n_field: F),+),+) -> $name<F> {
                $name {
                    $($field: $point::new($($n_field),+)),+
                }
            }
        }

        impl<F> $crate::traits::BezCurve<F> for $name<F>
                where F: ::num::Float + ::num::FromPrimitive {
            type Point = $point<F>;
            type Vector = $vector<F>;

            fn from_slice(slice: &[$point<F>]) -> $name<F> {
                let mut index = -1;
                $name {$($field: {
                    index += 1;
                    slice[index as usize]
                }),+}
            }

            fn interp_unbounded(&self, t: F) -> $point<F> {
                use $crate::traits::BezCurve;

                $(let $dim = $poly::new($(self.$dfield.$dim),+);)+
                $point::new($($dim.interp_unbounded(t)),+)
            }

            fn slope_unbounded(&self, t: F) -> $vector<F> {
                use $crate::traits::BezCurve;

                $(let $dim = $poly::new($(self.$dfield.$dim),+);)+
                $vector::new($($dim.slope_unbounded(t)),+)
            }

            #[inline]
            fn order() -> usize {
                $poly::<F>::order()
            }
        }

        impl<F> ::std::ops::Deref for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            type Target = [$point<F>];
            fn deref(&self) -> &[$point<F>] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts(self as *const $name<F> as *const $point<F>, count!($($field),+))
                }
            }
        }

        impl<F> ::std::ops::DerefMut for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            fn deref_mut(&mut self) -> &mut [$point<F>] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts_mut(self as *mut $name<F> as *mut $point<F>, count!($($field),+))
                }
            }
        }
    };
}<commit_msg>Fized bezier curve order calculations, added assertion<commit_after>// Vector/Point macros
macro_rules! n_pointvector {
    (ops $lhs:ident; $rhs:ident {$($field:ident),*}) => {
        impl<F: Float> ::std::ops::Add<$rhs<F>> for $lhs<F> {
            type Output = $lhs<F>;

            fn add(self, rhs: $rhs<F>) -> $lhs<F> {
                $lhs {
                    $($field: self.$field + rhs.$field),*
                }
            }
        }

        impl<F: Float> ::std::ops::Sub<$rhs<F>> for $lhs<F> {
            type Output = $lhs<F>;

            fn sub(self, rhs: $rhs<F>) -> $lhs<F> {
                $lhs {
                    $($field: self.$field - rhs.$field),*
                }
            }
        }
    };

    (float ops $name:ident {$($field:ident),+}) => {
        impl<F: Float> ::std::ops::Mul<F> for $name<F> {
            type Output = $name<F>;

            fn mul(self, rhs: F) -> $name<F> {
                $name {
                    $($field: self.$field * rhs),+
                }
            }
        }

        impl<F: Float> ::std::ops::Div<F> for $name<F> {
            type Output = $name<F>;

            fn div(self, rhs: F) -> $name<F> {
                $name {
                    $($field: self.$field / rhs),+
                }
            }
        }

        impl<F: Float> ::std::ops::Neg for $name<F> {
            type Output = $name<F>;

            fn neg(self) -> $name<F> {
                $name {
                    $($field: -self.$field),+
                }
            }
        }
    };

    (struct $dims:expr; $name:ident {$($field:ident: $f_ty:ident),+} $sibling:ident) => {
        #[derive(Debug, Clone, Copy)]
        pub struct $name<F: Float> {
            $(pub $field: F),+
        }

        impl<F: Float> $name<F> {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }
        }

        impl<'a, F: Float> ::std::convert::From<&'a [F]> for $name<F> {
            fn from(slice: &'a [F]) -> $name<F> {
                assert_eq!(slice.len(), count!($($field),+));
                let mut index = -1;
                $name{$($field: {
                    index += 1;
                    slice[index as usize]
                }),+}
            }
        }

        impl<F: Float> ::std::convert::Into<[F; $dims]> for $name<F> {
            fn into(self) -> [F; $dims] {
                [$(self.$field),*]
            }
        }

        impl<F: Float> ::std::convert::Into<($($f_ty),*)> for $name<F> {
            fn into(self) -> ($($f_ty),*) {
                ($(self.$field),*)
            }
        }

        impl<F: Float> ::std::convert::From<$sibling<F>> for $name<F> {
            fn from(sib: $sibling<F>) -> $name<F> {
                $name {
                    $($field: sib.$field),*
                }
            }
        }

        n_pointvector!(ops $name; $sibling {$($field),+});
        n_pointvector!(ops $name; $name {$($field),+});
        n_pointvector!(float ops $name {$($field),+});
    };

    ($dims:expr; $p_name:ident, $v_name:ident {$($field:ident),+}) => {
        n_pointvector!(struct $dims; $p_name {$($field: F),+} $v_name);
        n_pointvector!(struct $dims; $v_name {$($field: F),+} $p_name);

        impl<F: Float + FromPrimitive> $v_name<F> {
            pub fn len(self) -> F {
                ($(self.$field.powi(2) +)+ F::from_f32(0.0).unwrap()).sqrt()
            }

            pub fn normalize(self) -> $v_name<F> {
                self / self.len()
            }
        }
    }
}

// Polynomial Macros
macro_rules! count {
    ($idc:tt) => (1);
    ($($element:tt),*) => {{$(count!($element) +)* 0}};
}

macro_rules! n_bezier {
    ($name:ident {
        $($field:ident: $weight:expr),+
    } derived {
        $($dleft:ident - $dright:ident: $dweight:expr),+
    }) => {
        #[derive(Debug, Clone, Copy)]
        pub struct $name<F> where F: ::num::Float + ::num::FromPrimitive {
            $(pub $field: F),+
        }

        impl<F> $name<F> where F: ::num::Float + ::num::FromPrimitive {
            pub fn new($($field: F),+) -> $name<F> {
                $name {
                    $($field: $field),+
                }
            }
        }

        impl<F> $crate::traits::BezCurve<F> for $name<F>
                where F: ::num::Float + ::num::FromPrimitive {
            type Point = F;
            type Vector = F;

            fn from_slice(slice: &[F]) -> $name<F> {
                assert_eq!(slice.len() - 1, $name::<F>::order());
                let mut index = -1;
                $name {$($field: {
                    index += 1;
                    slice[index as usize]
                }),+}
            }

            fn interp_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($field),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $field =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        self.$field *
                        F::from_i32($weight).unwrap();
                )+
                $($field +)+ F::from_f32(0.0).unwrap()
            }

            fn slope_unbounded(&self, t: F) -> F {
                let t1 = F::from_f32(1.0).unwrap() - t;
                const COUNT: i32 = count!($($dleft),+) - 1;
                let mut factor = COUNT + 1;

                $(
                    factor -= 1;
                    let $dleft =
                        t1.powi(factor) *
                        t.powi(COUNT-factor) *
                        (self.$dleft - self.$dright) *
                        F::from_i32($dweight * (COUNT + 1)).unwrap();
                )+
                $($dleft +)+ F::from_f32(0.0).unwrap()
            }

            #[inline]
            fn order() -> usize {
                count!($($field),+)-1
            }
        }

        impl<F> ::std::ops::Deref for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            type Target = [F];
            fn deref(&self) -> &[F] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts(self as *const $name<F> as *const F, count!($($field),+))
                }
            }
        }

        impl<F> ::std::ops::DerefMut for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            fn deref_mut(&mut self) -> &mut [F] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts_mut(self as *mut $name<F> as *mut F, count!($($field),+))
                }
            }
        }
    }
}

macro_rules! bez_composite {
    ($name:ident<$poly:ident> {
        $($field:ident: $($n_field:ident),+;)+
    } -> <$point:ident; $vector:ident>;
        $($dim:ident = $($dfield:ident),+;)+) =>
    {
        #[derive(Debug, Clone, Copy)]
        pub struct $name<F: ::num::Float + ::num::FromPrimitive> {
            $(pub $field: $point<F>),+
        }

        impl<F: ::num::Float + ::num::FromPrimitive> $name<F> {
            pub fn new($($($n_field: F),+),+) -> $name<F> {
                $name {
                    $($field: $point::new($($n_field),+)),+
                }
            }
        }

        impl<F> $crate::traits::BezCurve<F> for $name<F>
                where F: ::num::Float + ::num::FromPrimitive {
            type Point = $point<F>;
            type Vector = $vector<F>;

            fn from_slice(slice: &[$point<F>]) -> $name<F> {
                assert_eq!(slice.len() - 1, $name::<F>::order());
                let mut index = -1;
                $name {$($field: {
                    index += 1;
                    slice[index as usize]
                }),+}
            }

            fn interp_unbounded(&self, t: F) -> $point<F> {
                use $crate::traits::BezCurve;

                $(let $dim = $poly::new($(self.$dfield.$dim),+);)+
                $point::new($($dim.interp_unbounded(t)),+)
            }

            fn slope_unbounded(&self, t: F) -> $vector<F> {
                use $crate::traits::BezCurve;

                $(let $dim = $poly::new($(self.$dfield.$dim),+);)+
                $vector::new($($dim.slope_unbounded(t)),+)
            }

            #[inline]
            fn order() -> usize {
                $poly::<F>::order()
            }
        }

        impl<F> ::std::ops::Deref for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            type Target = [$point<F>];
            fn deref(&self) -> &[$point<F>] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts(self as *const $name<F> as *const $point<F>, count!($($field),+))
                }
            }
        }

        impl<F> ::std::ops::DerefMut for $name<F> where F: ::num::Float + ::num::FromPrimitive {
            fn deref_mut(&mut self) -> &mut [$point<F>] {
                use std::slice;
                unsafe {
                    slice::from_raw_parts_mut(self as *mut $name<F> as *mut $point<F>, count!($($field),+))
                }
            }
        }
    };
}<|endoftext|>


<commit_before>//! Macros shared throughout the compiler-builtins implementation

/// The "main macro" used for defining intrinsics.
///
/// The compiler-builtins library is super platform-specific with tons of crazy
/// little tweaks for various platforms. As a result it *could* involve a lot fo
/// #[cfg] and macro soup, but the intention is that this macro alleviates a lof
/// of that complexity. Ideally this macro has all the weird ABI things
/// platforms need and elsewhere in this library it just looks like normal Rust
/// code.
///
/// This macro is structured to be invoked with a bunch of functions that looks
/// like:
///
///     intrinsics! {
///         pub extern "C" fn foo(a: i32) -> u32 {
///             // ...
///         }
///
///         #[nonstandard_attribute]
///         pub extern "C" fn bar(a: i32) -> u32 {
///             // ...
///         }
///     }
///
/// Each function is defined in a manner that looks like a normal Rust function.
/// The macro then accepts a few nonstandard attributes that can decorate
/// various functions. Each of the attributes is documented below with what it
/// can do, and each of them slightly tweaks how further expansion happens.
///
/// A quick overview of attributes supported right now are:
///
/// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the
///   C-compiled version if `feature = "c"` is specified.
/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and
///   the specified ABI everywhere else.
/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the
///   `"unadjusted"` abi on Win64 and the specified abi elsewhere.
/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer
///   intrinsics where the ABI is slightly tweaked on Windows platforms, but
///   it's a normal ABI elsewhere for returning a 128 bit integer.
/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM
///   their otherwise typical names to other prefixed ones.
///
macro_rules! intrinsics {
    () => ();

    // Right now there's a bunch of architecture-optimized intrinsics in the
    // stock compiler-rt implementation. Not all of these have been ported over
    // to Rust yet so when the `c` feature of this crate is enabled we fall back
    // to the architecture-specific versions which should be more optimized. The
    // purpose of this macro is to easily allow specifying this.
    //
    // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true,
    // will cause this crate's exported version of `$name` to just redirect to
    // the C implementation. No symbol named `$name` will be in the object file
    // for this crate itself.
    //
    // When the `#[cfg]` directive is false, or when the `c` feature is
    // disabled, the provided implementation is used instead.
    (
        #[use_c_shim_if($($cfg_clause:tt)*)]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (

        #[cfg(all(feature = "c", $($cfg_clause)*))]
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            extern $abi {
                fn $name($($argname: $ty),*) -> $ret;
            }
            unsafe {
                $name($($argname),*)
            }
        }

        #[cfg(not(all(feature = "c", $($cfg_clause)*)))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // We recognize the `#[aapcs_on_arm]` attribute here and generate the
    // same intrinsic but force it to have the `"aapcs"` calling convention on
    // ARM and `"C"` elsewhere.
    (
        #[aapcs_on_arm]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(target_arch = "arm")]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        #[cfg(not(target_arch = "arm"))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // Like aapcs above we recognize an attribute for the "unadjusted" abi on
    // win64 for some methods.
    (
        #[unadjusted_on_win64]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(all(windows, target_pointer_width = "64"))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        #[cfg(not(all(windows, target_pointer_width = "64")))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
    // calling convention. That's managed here with this "abi hack" which alters
    // the generated symbol's ABI.
    //
    // This will still define a function in this crate with the given name and
    // signature, but the actual symbol for the intrinsic may have a slightly
    // different ABI on win64.
    (
        #[win64_128bit_abi_hack]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(all(windows, target_pointer_width = "64"))]
        $(#[$($attr)*])*
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            $($body)*
        }

        #[cfg(all(windows, target_pointer_width = "64"))]
        pub mod $name {

            intrinsics! {
                pub extern $abi fn $name( $($argname: $ty),* )
                    -> ::macros::win64_128bit_abi_hack::U64x2
                {
                    let e: $ret = super::$name($($argname),*);
                    ::macros::win64_128bit_abi_hack::U64x2::from(e)
                }
            }
        }

        #[cfg(not(all(windows, target_pointer_width = "64")))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
    // build under `__aeabi_*` aliases, and LLVM will call these instead of the
    // original function. The aliasing here is used to generate these symbols in
    // the object file.
    (
        #[arm_aeabi_alias = $alias:ident]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(target_arch = "arm")]
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            $($body)*
        }

        #[cfg(target_arch = "arm")]
        pub mod $name {
            intrinsics! {
                pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret {
                    super::$name($($argname),*)
                }

                pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                    super::$name($($argname),*)
                }
            }
        }

        #[cfg(not(target_arch = "arm"))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // This is the final catch-all rule. At this point we just generate an
    // intrinsic with a conditional `#[no_mangle]` directive to avoid
    // interfereing with duplicate symbols and whatnot during testing.
    //
    // After the intrinsic is defined we just continue with the rest of the
    // input we were given.
    (
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        $(#[$($attr)*])*
        #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            $($body)*
        }

        intrinsics!($($rest)*);
    );
}

// Hack for LLVM expectations for ABI on windows. This is used by the
// `#[win64_128bit_abi_hack]` attribute recognized above
#[cfg(all(windows, target_pointer_width="64"))]
pub mod win64_128bit_abi_hack {
    #[repr(simd)]
    pub struct U64x2(u64, u64);

    impl From<i128> for U64x2 {
        fn from(i: i128) -> U64x2 {
            use int::LargeInt;
            let j = i as u128;
            U64x2(j.low(), j.high())
        }
    }

    impl From<u128> for U64x2 {
        fn from(i: u128) -> U64x2 {
            use int::LargeInt;
            U64x2(i.low(), i.high())
        }
    }
}
<commit_msg>Address review comments<commit_after>//! Macros shared throughout the compiler-builtins implementation

/// The "main macro" used for defining intrinsics.
///
/// The compiler-builtins library is super platform-specific with tons of crazy
/// little tweaks for various platforms. As a result it *could* involve a lot of
/// #[cfg] and macro soup, but the intention is that this macro alleviates a lot
/// of that complexity. Ideally this macro has all the weird ABI things
/// platforms need and elsewhere in this library it just looks like normal Rust
/// code.
///
/// This macro is structured to be invoked with a bunch of functions that looks
/// like:
///
///     intrinsics! {
///         pub extern "C" fn foo(a: i32) -> u32 {
///             // ...
///         }
///
///         #[nonstandard_attribute]
///         pub extern "C" fn bar(a: i32) -> u32 {
///             // ...
///         }
///     }
///
/// Each function is defined in a manner that looks like a normal Rust function.
/// The macro then accepts a few nonstandard attributes that can decorate
/// various functions. Each of the attributes is documented below with what it
/// can do, and each of them slightly tweaks how further expansion happens.
///
/// A quick overview of attributes supported right now are:
///
/// * `use_c_shim_if` - takes a #[cfg] directive and falls back to the
///   C-compiled version if `feature = "c"` is specified.
/// * `aapcs_on_arm` - forces the ABI of the function to be `"aapcs"` on ARM and
///   the specified ABI everywhere else.
/// * `unadjusted_on_win64` - like `aapcs_on_arm` this switches to the
///   `"unadjusted"` abi on Win64 and the specified abi elsewhere.
/// * `win64_128bit_abi_hack` - this attribute is used for 128-bit integer
///   intrinsics where the ABI is slightly tweaked on Windows platforms, but
///   it's a normal ABI elsewhere for returning a 128 bit integer.
/// * `arm_aeabi_alias` - handles the "aliasing" of various intrinsics on ARM
///   their otherwise typical names to other prefixed ones.
///
macro_rules! intrinsics {
    () => ();

    // Right now there's a bunch of architecture-optimized intrinsics in the
    // stock compiler-rt implementation. Not all of these have been ported over
    // to Rust yet so when the `c` feature of this crate is enabled we fall back
    // to the architecture-specific versions which should be more optimized. The
    // purpose of this macro is to easily allow specifying this.
    //
    // The argument to `use_c_shim_if` is a `#[cfg]` directive which, when true,
    // will cause this crate's exported version of `$name` to just redirect to
    // the C implementation. No symbol named `$name` will be in the object file
    // for this crate itself.
    //
    // When the `#[cfg]` directive is false, or when the `c` feature is
    // disabled, the provided implementation is used instead.
    (
        #[use_c_shim_if($($cfg_clause:tt)*)]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (

        #[cfg(all(feature = "c", $($cfg_clause)*))]
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            extern $abi {
                fn $name($($argname: $ty),*) -> $ret;
            }
            unsafe {
                $name($($argname),*)
            }
        }

        #[cfg(not(all(feature = "c", $($cfg_clause)*)))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // We recognize the `#[aapcs_on_arm]` attribute here and generate the
    // same intrinsic but force it to have the `"aapcs"` calling convention on
    // ARM and `"C"` elsewhere.
    (
        #[aapcs_on_arm]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(target_arch = "arm")]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        #[cfg(not(target_arch = "arm"))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // Like aapcs above we recognize an attribute for the "unadjusted" abi on
    // win64 for some methods.
    (
        #[unadjusted_on_win64]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(all(windows, target_pointer_width = "64"))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern "unadjusted" fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        #[cfg(not(all(windows, target_pointer_width = "64")))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // Some intrinsics on win64 which return a 128-bit integer have an.. unusual
    // calling convention. That's managed here with this "abi hack" which alters
    // the generated symbol's ABI.
    //
    // This will still define a function in this crate with the given name and
    // signature, but the actual symbol for the intrinsic may have a slightly
    // different ABI on win64.
    (
        #[win64_128bit_abi_hack]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(all(windows, target_pointer_width = "64"))]
        $(#[$($attr)*])*
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            $($body)*
        }

        #[cfg(all(windows, target_pointer_width = "64"))]
        pub mod $name {

            intrinsics! {
                pub extern $abi fn $name( $($argname: $ty),* )
                    -> ::macros::win64_128bit_abi_hack::U64x2
                {
                    let e: $ret = super::$name($($argname),*);
                    ::macros::win64_128bit_abi_hack::U64x2::from(e)
                }
            }
        }

        #[cfg(not(all(windows, target_pointer_width = "64")))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // A bunch of intrinsics on ARM are aliased in the standard compiler-rt
    // build under `__aeabi_*` aliases, and LLVM will call these instead of the
    // original function. The aliasing here is used to generate these symbols in
    // the object file.
    (
        #[arm_aeabi_alias = $alias:ident]
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        #[cfg(target_arch = "arm")]
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            $($body)*
        }

        #[cfg(target_arch = "arm")]
        pub mod $name {
            intrinsics! {
                pub extern "aapcs" fn $alias( $($argname: $ty),* ) -> $ret {
                    super::$name($($argname),*)
                }
            }
        }

        #[cfg(not(target_arch = "arm"))]
        intrinsics! {
            $(#[$($attr)*])*
            pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
                $($body)*
            }
        }

        intrinsics!($($rest)*);
    );

    // This is the final catch-all rule. At this point we just generate an
    // intrinsic with a conditional `#[no_mangle]` directive to avoid
    // interfereing with duplicate symbols and whatnot during testing.
    //
    // After the intrinsic is defined we just continue with the rest of the
    // input we were given.
    (
        $(#[$($attr:tt)*])*
        pub extern $abi:tt fn $name:ident( $($argname:ident:  $ty:ty),* ) -> $ret:ty {
            $($body:tt)*
        }

        $($rest:tt)*
    ) => (
        $(#[$($attr)*])*
        #[cfg_attr(not(feature = "mangled-names"), no_mangle)]
        pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
            $($body)*
        }

        intrinsics!($($rest)*);
    );
}

// Hack for LLVM expectations for ABI on windows. This is used by the
// `#[win64_128bit_abi_hack]` attribute recognized above
#[cfg(all(windows, target_pointer_width="64"))]
pub mod win64_128bit_abi_hack {
    #[repr(simd)]
    pub struct U64x2(u64, u64);

    impl From<i128> for U64x2 {
        fn from(i: i128) -> U64x2 {
            use int::LargeInt;
            let j = i as u128;
            U64x2(j.low(), j.high())
        }
    }

    impl From<u128> for U64x2 {
        fn from(i: u128) -> U64x2 {
            use int::LargeInt;
            U64x2(i.low(), i.high())
        }
    }
}
<|endoftext|>