<commit_before>use super::*;

pub(super) fn mod_contents(p: &mut Parser) {
    attributes::inner_attributes(p);
    while !p.at(EOF) {
        item(p);
    }
}

pub(super) const ITEM_FIRST: TokenSet = token_set![
    EXTERN_KW,
    MOD_KW,
    USE_KW,
    STRUCT_KW,
    FN_KW,
    PUB_KW,
    POUND,
];

fn item(p: &mut Parser) {
    let item = p.start();
    attributes::outer_attributes(p);
    visibility(p);
    let la = p.raw_lookahead(1);
    let item_kind = match p.current() {
        EXTERN_KW if la == CRATE_KW => {
            extern_crate_item(p);
            EXTERN_CRATE_ITEM
        }
        MOD_KW => {
            mod_item(p);
            MOD_ITEM
        }
        USE_KW => {
            use_item(p);
            USE_ITEM
        }
        STRUCT_KW => {
            struct_item(p);
            STRUCT_ITEM
        }
        FN_KW => {
            fn_item(p);
            FN_ITEM
        }
        err_token => {
            item.abandon(p);
            let message = if err_token == SEMI {
                //TODO: if the item is incomplete, this message is misleading
                "expected item, found `;`\n\
                consider removing this semicolon"
            } else {
                "expected item"
            };
            p.err_and_bump(message);
            return;
        }
    };
    item.complete(p, item_kind);
}

fn struct_item(p: &mut Parser) {
    assert!(p.at(STRUCT_KW));
    p.bump();

    if !p.expect(IDENT) {
        return;
    }
    generic_parameters(p);
    match p.current() {
        WHERE_KW => {
            where_clause(p);
            match p.current() {
                SEMI => {
                    p.bump();
                    return;
                }
                L_CURLY => named_fields(p),
                _ => { //TODO: special case `(` error message
                    p.error()
                        .message("expected `;` or `{`")
                        .emit();
                    return;
                }
            }
        }
        SEMI => {
            p.bump();
            return;
        }
        L_CURLY => named_fields(p),
        L_PAREN => {
            pos_fields(p);
            p.expect(SEMI);
        }
        _ => {
            p.error()
                .message("expected `;`, `{`, or `(`")
                .emit();
            return;
        }
    }
}

fn named_fields(p: &mut Parser) {
    p.curly_block(|p| comma_list(p, EOF, |p| {
        named_field(p);
        true
    }));

    fn named_field(p: &mut Parser) {
        let field = p.start();
        visibility(p);
        if p.expect(IDENT) && p.expect(COLON) {
            types::type_ref(p);
        };
        field.complete(p, NAMED_FIELD);
    }
}

fn pos_fields(p: &mut Parser) {
    if !p.expect(L_PAREN) {
        return;
    }
    while !p.at(R_PAREN) && !p.at(EOF) {
        let pos_field = p.start();
        visibility(p);
        types::type_ref(p);
        pos_field.complete(p, POS_FIELD);

        if !p.at(R_PAREN) {
            p.expect(COMMA);
        }
    }
    p.expect(R_PAREN);
}

fn generic_parameters(_: &mut Parser) {}

fn where_clause(_: &mut Parser) {}

fn extern_crate_item(p: &mut Parser) {
    assert!(p.at(EXTERN_KW));
    p.bump();
    assert!(p.at(CRATE_KW));
    p.bump();

    p.expect(IDENT) && alias(p) && p.expect(SEMI);
}

fn mod_item(p: &mut Parser) {
    assert!(p.at(MOD_KW));
    p.bump();

    if p.expect(IDENT) && !p.eat(SEMI) {
        p.curly_block(mod_contents);
    }
}

pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool {
    kind == STAR || kind == L_CURLY
}

fn use_item(p: &mut Parser) {
    assert!(p.at(USE_KW));
    p.bump();

    use_tree(p);
    p.expect(SEMI);

    fn use_tree(p: &mut Parser){
        let la = p.raw_lookahead(1);
        let m = p.start();
        match (p.current(), la) {
            (STAR, _) => {
                p.bump();
            }
            (COLONCOLON, STAR) => {
                p.bump();
                p.bump();
            }
            (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
                if p.at(COLONCOLON) {
                    p.bump();
                }
                nested_trees(p);
            }
            _ if paths::is_path_start(p) => {
                paths::use_path(p);
                match p.current() {
                    AS_KW => {
                        alias(p);
                    }
                    COLONCOLON => {
                        p.bump();
                        match p.current() {
                            STAR => {
                                p.bump();
                            }
                            L_CURLY => nested_trees(p),
                            _ => {
                                // is this unreachable?
                                p.error()
                                    .message("expected `{` or `*`")
                                    .emit();
                            }
                        }
                    }
                    _ => (),
                }
            }
            _ => {
                m.abandon(p);
                p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
                return;
            },
        }
        m.complete(p, USE_TREE);
    }

    fn nested_trees(p: &mut Parser) {
        assert!(p.at(L_CURLY));
        p.bump();
        while !p.at(EOF) && !p.at(R_CURLY) {
            use_tree(p);
            if !p.at(R_CURLY) {
                p.expect(COMMA);
            }
        }
        p.expect(R_CURLY);
    }
}

fn fn_item(p: &mut Parser) {
    assert!(p.at(FN_KW));
    p.bump();

    p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN)
        && p.curly_block(|_| ());
}

<commit_msg>Simplify<commit_after>use super::*;

pub(super) fn mod_contents(p: &mut Parser) {
    attributes::inner_attributes(p);
    while !p.at(EOF) {
        item(p);
    }
}

pub(super) const ITEM_FIRST: TokenSet = token_set![
    EXTERN_KW,
    MOD_KW,
    USE_KW,
    STRUCT_KW,
    FN_KW,
    PUB_KW,
    POUND,
];

fn item(p: &mut Parser) {
    let item = p.start();
    attributes::outer_attributes(p);
    visibility(p);
    let la = p.raw_lookahead(1);
    let item_kind = match p.current() {
        EXTERN_KW if la == CRATE_KW => {
            extern_crate_item(p);
            EXTERN_CRATE_ITEM
        }
        MOD_KW => {
            mod_item(p);
            MOD_ITEM
        }
        USE_KW => {
            use_item(p);
            USE_ITEM
        }
        STRUCT_KW => {
            struct_item(p);
            STRUCT_ITEM
        }
        FN_KW => {
            fn_item(p);
            FN_ITEM
        }
        err_token => {
            item.abandon(p);
            let message = if err_token == SEMI {
                //TODO: if the item is incomplete, this message is misleading
                "expected item, found `;`\n\
                consider removing this semicolon"
            } else {
                "expected item"
            };
            p.err_and_bump(message);
            return;
        }
    };
    item.complete(p, item_kind);
}

fn struct_item(p: &mut Parser) {
    assert!(p.at(STRUCT_KW));
    p.bump();

    if !p.expect(IDENT) {
        return;
    }
    generic_parameters(p);
    match p.current() {
        WHERE_KW => {
            where_clause(p);
            match p.current() {
                SEMI => {
                    p.bump();
                    return;
                }
                L_CURLY => named_fields(p),
                _ => { //TODO: special case `(` error message
                    p.error()
                        .message("expected `;` or `{`")
                        .emit();
                    return;
                }
            }
        }
        SEMI => {
            p.bump();
            return;
        }
        L_CURLY => named_fields(p),
        L_PAREN => {
            pos_fields(p);
            p.expect(SEMI);
        }
        _ => {
            p.error()
                .message("expected `;`, `{`, or `(`")
                .emit();
            return;
        }
    }
}

fn named_fields(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    p.bump();
    while !p.at(R_CURLY) && !p.at(EOF) {
        named_field(p);
        if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);

    fn named_field(p: &mut Parser) {
        let field = p.start();
        visibility(p);
        if p.expect(IDENT) {
            p.expect(COLON);
            types::type_ref(p);
            field.complete(p, NAMED_FIELD);
        } else {
            field.abandon(p);
            p.err_and_bump("expected field declaration");
        }
    }
}

fn pos_fields(p: &mut Parser) {
    if !p.expect(L_PAREN) {
        return;
    }
    while !p.at(R_PAREN) && !p.at(EOF) {
        let pos_field = p.start();
        visibility(p);
        types::type_ref(p);
        pos_field.complete(p, POS_FIELD);

        if !p.at(R_PAREN) {
            p.expect(COMMA);
        }
    }
    p.expect(R_PAREN);
}

fn generic_parameters(_: &mut Parser) {}

fn where_clause(_: &mut Parser) {}

fn extern_crate_item(p: &mut Parser) {
    assert!(p.at(EXTERN_KW));
    p.bump();
    assert!(p.at(CRATE_KW));
    p.bump();

    p.expect(IDENT) && alias(p) && p.expect(SEMI);
}

fn mod_item(p: &mut Parser) {
    assert!(p.at(MOD_KW));
    p.bump();

    if p.expect(IDENT) && !p.eat(SEMI) {
        p.curly_block(mod_contents);
    }
}

pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool {
    kind == STAR || kind == L_CURLY
}

fn use_item(p: &mut Parser) {
    assert!(p.at(USE_KW));
    p.bump();

    use_tree(p);
    p.expect(SEMI);

    fn use_tree(p: &mut Parser){
        let la = p.raw_lookahead(1);
        let m = p.start();
        match (p.current(), la) {
            (STAR, _) => {
                p.bump();
            }
            (COLONCOLON, STAR) => {
                p.bump();
                p.bump();
            }
            (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
                if p.at(COLONCOLON) {
                    p.bump();
                }
                nested_trees(p);
            }
            _ if paths::is_path_start(p) => {
                paths::use_path(p);
                match p.current() {
                    AS_KW => {
                        alias(p);
                    }
                    COLONCOLON => {
                        p.bump();
                        match p.current() {
                            STAR => {
                                p.bump();
                            }
                            L_CURLY => nested_trees(p),
                            _ => {
                                // is this unreachable?
                                p.error()
                                    .message("expected `{` or `*`")
                                    .emit();
                            }
                        }
                    }
                    _ => (),
                }
            }
            _ => {
                m.abandon(p);
                p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
                return;
            },
        }
        m.complete(p, USE_TREE);
    }

    fn nested_trees(p: &mut Parser) {
        assert!(p.at(L_CURLY));
        p.bump();
        while !p.at(EOF) && !p.at(R_CURLY) {
            use_tree(p);
            if !p.at(R_CURLY) {
                p.expect(COMMA);
            }
        }
        p.expect(R_CURLY);
    }
}

fn fn_item(p: &mut Parser) {
    assert!(p.at(FN_KW));
    p.bump();

    p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN)
        && p.curly_block(|_| ());
}

<|endoftext|>


<commit_before><commit_msg>Refactoring to clean up sub() in Rust<commit_after><|endoftext|>


<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 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) -> BTreeSet<PathBuf> {
    fn potentially_empty_dirs(mut result: BTreeSet<PathBuf>, mut target_dirs: VecDeque<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()
                    .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)
            },
        }
    }

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

#[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 trim_current_dir_prefix_should_return_trimmed() {
        let path_names = [
            (""   , "./"    ),
            (""   , "././"  ),
            (""   , "./././"),
            ("a"  , "./a"   ),
            ("a/" , "./a/"  ),
            ("a/b", "./a/b" ),
        ];
        for &(ref correct, ref 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() {
        let helper = Helper::new("la_Ok");
        helper.create_dirs_and_files();

        let empty_vec: Vec<String> = Vec::new();

        assert_eq!(vec![helper.f1.clone(), helper.d5.clone(), helper.d2.clone(), helper.d6.clone()], la(helper.path_to_d1()).unwrap());
        assert_eq!(vec![helper.d3.clone(), helper.f2.clone()]                                      , la(helper.path_to_d2()).unwrap());
        assert_eq!(vec![helper.d4.clone(), helper.f3.clone()]                                      , la(helper.path_to_d3()).unwrap());
        assert_eq!(empty_vec                                                                       , la(helper.path_to_d4()).unwrap());
        assert_eq!(vec![helper.f4.clone()]                                                         , la(helper.path_to_d5()).unwrap());
        assert_eq!(empty_vec                                                                       , la(helper.path_to_d6()).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));

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

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

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

        helper.remove_dirs_and_files();
    }
}
<commit_msg>[Test] Fix failure temporary<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 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) -> BTreeSet<PathBuf> {
    fn potentially_empty_dirs(mut result: BTreeSet<PathBuf>, mut target_dirs: VecDeque<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()
                    .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)
            },
        }
    }

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

#[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 trim_current_dir_prefix_should_return_trimmed() {
        let path_names = [
            (""   , "./"    ),
            (""   , "././"  ),
            (""   , "./././"),
            ("a"  , "./a"   ),
            ("a/" , "./a/"  ),
            ("a/b", "./a/b" ),
        ];
        for &(ref correct, ref 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 empty_btree_set: BTreeSet<String> = BTreeSet::new();

        let correct = to_btree_set(vec![helper.d2.clone(), helper.d5.clone(), helper.d6.clone(), helper.f1.clone()]);
        assert_eq!(correct, to_btree_set(la(helper.path_to_d1()).unwrap()));
        let correct = to_btree_set(vec![helper.d3.clone(), helper.f2.clone()]);
        assert_eq!(correct, to_btree_set(la(helper.path_to_d2()).unwrap()));
        let correct = to_btree_set(vec![helper.d4.clone(), helper.f3.clone()]);
        assert_eq!(correct        , to_btree_set(la(helper.path_to_d3()).unwrap()));
        assert_eq!(empty_btree_set, to_btree_set(la(helper.path_to_d4()).unwrap()));
        let correct = to_btree_set(vec![helper.f4.clone()]);
        assert_eq!(correct        , to_btree_set(la(helper.path_to_d5()).unwrap()));
        assert_eq!(empty_btree_set, to_btree_set(la(helper.path_to_d6()).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));

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

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

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

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


<commit_before><commit_msg>mv: add OverwriteMode match in specific case<commit_after><|endoftext|>


<commit_before>use anyhow::{Context, Error};
use flate2::read::GzDecoder;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use tar::Archive;

const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";

#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub(crate) enum PkgType {
    Rust,
    RustSrc,
    Cargo,
    Rls,
    RustAnalyzer,
    Clippy,
    Rustfmt,
    LlvmTools,
    Miri,
    Other(String),
}

impl PkgType {
    pub(crate) fn from_component(component: &str) -> Self {
        match component {
            "rust" => PkgType::Rust,
            "rust-src" => PkgType::RustSrc,
            "cargo" => PkgType::Cargo,
            "rls" | "rls-preview" => PkgType::Rls,
            "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
            "clippy" | "clippy-preview" => PkgType::Clippy,
            "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
            "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
            "miri" | "miri-preview" => PkgType::Miri,
            other => PkgType::Other(other.into()),
        }
    }

    /// The directory containing the `Cargo.toml` of this component inside the monorepo, to
    /// retrieve the source code version. If `None` is returned Rust's version will be used.
    fn rust_monorepo_path(&self) -> Option<&'static str> {
        match self {
            PkgType::Cargo => Some("src/tools/cargo"),
            PkgType::Rls => Some("src/tools/rls"),
            PkgType::RustAnalyzer => Some("src/tools/rust-analyzer/crates/rust-analyzer"),
            PkgType::Clippy => Some("src/tools/clippy"),
            PkgType::Rustfmt => Some("src/tools/rustfmt"),
            PkgType::Miri => Some("src/tools/miri"),
            PkgType::Rust => None,
            PkgType::RustSrc => None,
            PkgType::LlvmTools => None,
            PkgType::Other(_) => None,
        }
    }

    /// First part of the tarball name.
    fn tarball_component_name(&self) -> &str {
        match self {
            PkgType::Rust => "rust",
            PkgType::RustSrc => "rust-src",
            PkgType::Cargo => "cargo",
            PkgType::Rls => "rls",
            PkgType::RustAnalyzer => "rust-analyzer",
            PkgType::Clippy => "clippy",
            PkgType::Rustfmt => "rustfmt",
            PkgType::LlvmTools => "llvm-tools",
            PkgType::Miri => "miri",
            PkgType::Other(component) => component,
        }
    }

    /// Whether this package has the same version as Rust itself, or has its own `version` and
    /// `git-commit-hash` files inside the tarball.
    fn should_use_rust_version(&self) -> bool {
        match self {
            PkgType::Cargo => false,
            PkgType::Rls => false,
            PkgType::RustAnalyzer => false,
            PkgType::Clippy => false,
            PkgType::Rustfmt => false,
            PkgType::LlvmTools => false,
            PkgType::Miri => false,

            PkgType::Rust => true,
            PkgType::RustSrc => true,
            PkgType::Other(_) => true,
        }
    }
}

#[derive(Debug, Default, Clone)]
pub(crate) struct VersionInfo {
    pub(crate) version: Option<String>,
    pub(crate) git_commit: Option<String>,
    pub(crate) present: bool,
}

pub(crate) struct Versions {
    channel: String,
    rustc_version: String,
    monorepo_root: PathBuf,
    dist_path: PathBuf,
    package_versions: HashMap<PkgType, String>,
    versions: HashMap<PkgType, VersionInfo>,
}

impl Versions {
    pub(crate) fn new(
        channel: &str,
        dist_path: &Path,
        monorepo_root: &Path,
    ) -> Result<Self, Error> {
        Ok(Self {
            channel: channel.into(),
            rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version"))
                .context("failed to read the rustc version from src/version")?
                .trim()
                .to_string(),
            monorepo_root: monorepo_root.into(),
            dist_path: dist_path.into(),
            package_versions: HashMap::new(),
            versions: HashMap::new(),
        })
    }

    pub(crate) fn channel(&self) -> &str {
        &self.channel
    }

    pub(crate) fn version(&mut self, mut package: &PkgType) -> Result<VersionInfo, Error> {
        if package.should_use_rust_version() {
            package = &PkgType::Rust;
        }

        match self.versions.get(package) {
            Some(version) => Ok(version.clone()),
            None => {
                let version_info = self.load_version_from_tarball(package)?;
                self.versions.insert(package.clone(), version_info.clone());
                Ok(version_info)
            }
        }
    }

    fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
        let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
        let tarball = self.dist_path.join(tarball_name);

        let file = match File::open(&tarball) {
            Ok(file) => file,
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
                // Missing tarballs do not return an error, but return empty data.
                return Ok(VersionInfo::default());
            }
            Err(err) => return Err(err.into()),
        };
        let mut tar = Archive::new(GzDecoder::new(file));

        let mut version = None;
        let mut git_commit = None;
        for entry in tar.entries()? {
            let mut entry = entry?;

            let dest;
            match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
                Some("version") => dest = &mut version,
                Some("git-commit-hash") => dest = &mut git_commit,
                _ => continue,
            }
            let mut buf = String::new();
            entry.read_to_string(&mut buf)?;
            *dest = Some(buf);

            // Short circuit to avoid reading the whole tar file if not necessary.
            if version.is_some() && git_commit.is_some() {
                break;
            }
        }

        Ok(VersionInfo { version, git_commit, present: true })
    }

    pub(crate) fn disable_version(&mut self, package: &PkgType) {
        match self.versions.get_mut(package) {
            Some(version) => {
                *version = VersionInfo::default();
            }
            None => {
                self.versions.insert(package.clone(), VersionInfo::default());
            }
        }
    }

    pub(crate) fn tarball_name(
        &mut self,
        package: &PkgType,
        target: &str,
    ) -> Result<String, Error> {
        Ok(format!(
            "{}-{}-{}.tar.gz",
            package.tarball_component_name(),
            self.package_version(package).with_context(|| format!(
                "failed to get the package version for component {:?}",
                package,
            ))?,
            target
        ))
    }

    pub(crate) fn package_version(&mut self, package: &PkgType) -> Result<String, Error> {
        match self.package_versions.get(package) {
            Some(release) => Ok(release.clone()),
            None => {
                let version = match package.rust_monorepo_path() {
                    Some(path) => {
                        let path = self.monorepo_root.join(path).join("Cargo.toml");
                        let cargo_toml: CargoToml = toml::from_slice(&std::fs::read(path)?)?;
                        cargo_toml.package.version
                    }
                    None => self.rustc_version.clone(),
                };

                let release = match self.channel.as_str() {
                    "stable" => version,
                    "beta" => "beta".into(),
                    "nightly" => "nightly".into(),
                    _ => format!("{}-dev", version),
                };

                self.package_versions.insert(package.clone(), release.clone());
                Ok(release)
            }
        }
    }
}

#[derive(serde::Deserialize)]
struct CargoToml {
    package: CargoTomlPackage,
}

#[derive(serde::Deserialize)]
struct CargoTomlPackage {
    version: String,
}
<commit_msg>build-manifest: handle rust-src being target-independent<commit_after>use anyhow::{Context, Error};
use flate2::read::GzDecoder;
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use tar::Archive;

const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";

#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub(crate) enum PkgType {
    Rust,
    RustSrc,
    Cargo,
    Rls,
    RustAnalyzer,
    Clippy,
    Rustfmt,
    LlvmTools,
    Miri,
    Other(String),
}

impl PkgType {
    pub(crate) fn from_component(component: &str) -> Self {
        match component {
            "rust" => PkgType::Rust,
            "rust-src" => PkgType::RustSrc,
            "cargo" => PkgType::Cargo,
            "rls" | "rls-preview" => PkgType::Rls,
            "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
            "clippy" | "clippy-preview" => PkgType::Clippy,
            "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
            "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
            "miri" | "miri-preview" => PkgType::Miri,
            other => PkgType::Other(other.into()),
        }
    }

    /// The directory containing the `Cargo.toml` of this component inside the monorepo, to
    /// retrieve the source code version. If `None` is returned Rust's version will be used.
    fn rust_monorepo_path(&self) -> Option<&'static str> {
        match self {
            PkgType::Cargo => Some("src/tools/cargo"),
            PkgType::Rls => Some("src/tools/rls"),
            PkgType::RustAnalyzer => Some("src/tools/rust-analyzer/crates/rust-analyzer"),
            PkgType::Clippy => Some("src/tools/clippy"),
            PkgType::Rustfmt => Some("src/tools/rustfmt"),
            PkgType::Miri => Some("src/tools/miri"),
            PkgType::Rust => None,
            PkgType::RustSrc => None,
            PkgType::LlvmTools => None,
            PkgType::Other(_) => None,
        }
    }

    /// First part of the tarball name.
    fn tarball_component_name(&self) -> &str {
        match self {
            PkgType::Rust => "rust",
            PkgType::RustSrc => "rust-src",
            PkgType::Cargo => "cargo",
            PkgType::Rls => "rls",
            PkgType::RustAnalyzer => "rust-analyzer",
            PkgType::Clippy => "clippy",
            PkgType::Rustfmt => "rustfmt",
            PkgType::LlvmTools => "llvm-tools",
            PkgType::Miri => "miri",
            PkgType::Other(component) => component,
        }
    }

    /// Whether this package has the same version as Rust itself, or has its own `version` and
    /// `git-commit-hash` files inside the tarball.
    fn should_use_rust_version(&self) -> bool {
        match self {
            PkgType::Cargo => false,
            PkgType::Rls => false,
            PkgType::RustAnalyzer => false,
            PkgType::Clippy => false,
            PkgType::Rustfmt => false,
            PkgType::LlvmTools => false,
            PkgType::Miri => false,

            PkgType::Rust => true,
            PkgType::RustSrc => true,
            PkgType::Other(_) => true,
        }
    }

    /// Whether this package is target-independent or not.
    fn target_independent(&self) -> bool {
        *self == PkgType::RustSrc
    }
}

#[derive(Debug, Default, Clone)]
pub(crate) struct VersionInfo {
    pub(crate) version: Option<String>,
    pub(crate) git_commit: Option<String>,
    pub(crate) present: bool,
}

pub(crate) struct Versions {
    channel: String,
    rustc_version: String,
    monorepo_root: PathBuf,
    dist_path: PathBuf,
    package_versions: HashMap<PkgType, String>,
    versions: HashMap<PkgType, VersionInfo>,
}

impl Versions {
    pub(crate) fn new(
        channel: &str,
        dist_path: &Path,
        monorepo_root: &Path,
    ) -> Result<Self, Error> {
        Ok(Self {
            channel: channel.into(),
            rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version"))
                .context("failed to read the rustc version from src/version")?
                .trim()
                .to_string(),
            monorepo_root: monorepo_root.into(),
            dist_path: dist_path.into(),
            package_versions: HashMap::new(),
            versions: HashMap::new(),
        })
    }

    pub(crate) fn channel(&self) -> &str {
        &self.channel
    }

    pub(crate) fn version(&mut self, mut package: &PkgType) -> Result<VersionInfo, Error> {
        if package.should_use_rust_version() {
            package = &PkgType::Rust;
        }

        match self.versions.get(package) {
            Some(version) => Ok(version.clone()),
            None => {
                let version_info = self.load_version_from_tarball(package)?;
                self.versions.insert(package.clone(), version_info.clone());
                Ok(version_info)
            }
        }
    }

    fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> {
        let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?;
        let tarball = self.dist_path.join(tarball_name);

        let file = match File::open(&tarball) {
            Ok(file) => file,
            Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
                // Missing tarballs do not return an error, but return empty data.
                return Ok(VersionInfo::default());
            }
            Err(err) => return Err(err.into()),
        };
        let mut tar = Archive::new(GzDecoder::new(file));

        let mut version = None;
        let mut git_commit = None;
        for entry in tar.entries()? {
            let mut entry = entry?;

            let dest;
            match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) {
                Some("version") => dest = &mut version,
                Some("git-commit-hash") => dest = &mut git_commit,
                _ => continue,
            }
            let mut buf = String::new();
            entry.read_to_string(&mut buf)?;
            *dest = Some(buf);

            // Short circuit to avoid reading the whole tar file if not necessary.
            if version.is_some() && git_commit.is_some() {
                break;
            }
        }

        Ok(VersionInfo { version, git_commit, present: true })
    }

    pub(crate) fn disable_version(&mut self, package: &PkgType) {
        match self.versions.get_mut(package) {
            Some(version) => {
                *version = VersionInfo::default();
            }
            None => {
                self.versions.insert(package.clone(), VersionInfo::default());
            }
        }
    }

    pub(crate) fn tarball_name(
        &mut self,
        package: &PkgType,
        target: &str,
    ) -> Result<String, Error> {
        let component_name = package.tarball_component_name();
        let version = self.package_version(package).with_context(|| {
            format!("failed to get the package version for component {:?}", package,)
        })?;
        if package.target_independent() {
            Ok(format!("{}-{}.tar.gz", component_name, version))
        } else {
            Ok(format!("{}-{}-{}.tar.gz", component_name, version, target))
        }
    }

    pub(crate) fn package_version(&mut self, package: &PkgType) -> Result<String, Error> {
        match self.package_versions.get(package) {
            Some(release) => Ok(release.clone()),
            None => {
                let version = match package.rust_monorepo_path() {
                    Some(path) => {
                        let path = self.monorepo_root.join(path).join("Cargo.toml");
                        let cargo_toml: CargoToml = toml::from_slice(&std::fs::read(path)?)?;
                        cargo_toml.package.version
                    }
                    None => self.rustc_version.clone(),
                };

                let release = match self.channel.as_str() {
                    "stable" => version,
                    "beta" => "beta".into(),
                    "nightly" => "nightly".into(),
                    _ => format!("{}-dev", version),
                };

                self.package_versions.insert(package.clone(), release.clone());
                Ok(release)
            }
        }
    }
}

#[derive(serde::Deserialize)]
struct CargoToml {
    package: CargoTomlPackage,
}

#[derive(serde::Deserialize)]
struct CargoTomlPackage {
    version: String,
}
<|endoftext|>


<commit_before>
use wtools::vector;
use wtools::vector::left_index;

//

#[test]
fn append_vectors_once_trivial()
{
  println!( "empty vector" );
  let mut dst: Vec<u8> = vec![];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  let exp: Vec<u8> = vec![];
  assert_eq!( *got, exp );

  println!( "dst - filled, src - empty" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is unical elements" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 3, 4 ], vec![ 5, 6 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4, 5, 6 ] );

  println!( "dst - filled, src - filled, some is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 3 ], vec![ 4, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2, 3, 4 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 1 ], vec![ 2, 2 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut dst: Vec<u8> = vec![ 1, 2 ];
  let src: Vec<Vec<u8>> = vec![ vec![ 1, 2 ], vec![ 2, 1 ] ];
  let got = vector::append_vectors_once( &mut dst, &src, None::<fn(_)> );
  assert_eq!( *got, vec![ 1, 2 ] );
}

//

#[test]
fn left_index()
{
  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_equalizer()
{
  fn equalizer( src1 : &u8, src2 : &u8 ) -> bool
  {
    *src1 == *src2
  }

  /* */

  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_evaluator()
{
  fn evaluator1( src : &u8 ) -> u8
  {
    *src
  }

  /* */

  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_two_evaluators()
{
  fn evaluator1( src : &u8 ) -> u8
  {
    *src
  }
  fn evaluator2( src : &u8 ) -> u8
  {
    *src
  }

  /* */

  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

/*
  append_vectors_once_trivial
  left_index_trivial
  left_index_with_equalizer
*/
<commit_msg>Rewrite test routine `append_vectors_once`<commit_after>
use wtools::vector;
use wtools::vector::{ left_index, append_vectors_once };

//

#[test]
fn append_vectors_once()
{
  println!( "empty vector" );
  let mut appender: append_vectors_once<u8> = append_vectors_once::default();
  let got = appender.call();
  let exp: Vec<u8> = vec![];
  assert_eq!( got, exp );

  println!( "dst - filled, src - empty" );
  let mut appender: append_vectors_once<u8> = append_vectors_once::default();
  appender.dst( vec![ 1, 2 ] );
  let got = appender.call();
  assert_eq!( got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is unical elements" );
  let mut appender: append_vectors_once<u8> = append_vectors_once::default();
  appender.dst( vec![ 1, 2 ] );
  appender.src( vec![ vec![ 3, 4 ], vec![ 5, 6 ] ] );
  let got = appender.call();
  assert_eq!( *got, vec![ 1, 2, 3, 4, 5, 6 ] );

  println!( "dst - filled, src - filled, some is duplicated" );
  let mut appender: append_vectors_once<u8> = append_vectors_once::default();
  appender.dst( vec![ 1, 2 ] );
  appender.src( vec![ vec![ 1, 3 ], vec![ 2, 4 ] ] );
  let got = appender.call();
  assert_eq!( got, vec![ 1, 2, 3, 4 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut appender: append_vectors_once<u8> = append_vectors_once::default();
  appender.dst( vec![ 1, 2 ] );
  appender.src( vec![ vec![ 1, 1 ], vec![ 2, 2 ] ] );
  let got = appender.call();
  assert_eq!( got, vec![ 1, 2 ] );

  println!( "dst - filled, src - filled, all is duplicated" );
  let mut appender: append_vectors_once<u8> = append_vectors_once::default();
  appender.dst( vec![ 1, 2 ] );
  appender.src( vec![ vec![ 1, 2 ], vec![ 2, 1 ] ] );
  let got = appender.call();
  assert_eq!( got, vec![ 1, 2 ] );
}

//

#[test]
fn left_index()
{
  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_equalizer()
{
  fn equalizer( src1 : &u8, src2 : &u8 ) -> bool
  {
    *src1 == *src2
  }

  /* */

  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  src.on_equalize( equalizer );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_evaluator()
{
  fn evaluator1( src : &u8 ) -> u8
  {
    *src
  }

  /* */

  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

//

#[test]
fn left_index_with_two_evaluators()
{
  fn evaluator1( src : &u8 ) -> u8
  {
    *src
  }
  fn evaluator2( src : &u8 ) -> u8
  {
    *src
  }

  /* */

  println!( "empty vector" );
  let mut src : left_index<u8> = left_index::default();
  src.ins( 1 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, not matches" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 4 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, None );

  println!( "filled vector, matches one" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 3 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches several" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 1, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, Some( 1 ) );

  println!( "filled vector, matches all" );
  let mut src : left_index<u8> = left_index::default();
  src.src( vec![ 2, 2, 2 ] );
  src.ins( 2 );
  src.on_evaluate1( evaluator1 );
  src.on_evaluate1( evaluator2 );
  let got = src.call();
  assert_eq!( got, Some( 0 ) );
}

/*
  append_vectors_once_trivial
  left_index_trivial
  left_index_with_equalizer
*/
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::str::FromStr;
use datatable::*;

pub struct Loader<'a> {
	file: &'a str,
	delimiter: char,
}

impl<'a> Loader<'a> {

	/// Load the file from the loader with given delimiter.
	///
	/// Pretty rudimentary with poor error handling.
	pub fn load_file(self) -> Result<DataTable, io::Error> {
		let f = try!(File::open(self.file));
		let reader = BufReader::new(f);

		let mut table = DataTable::empty();

		// Should handle header here

		let mut lines = reader.lines();

		if let Some(line) = lines.next() {
			let line = try!(line);
			let values = line.split(self.delimiter);

			for val in values {
				let mut column = DataCols::<f64>::empty();
				// Unwrap and panic for now.
				// Should handle more carefully in future.
				column.data.push(f64::from_str(val).unwrap());

				table.data_cols.push(column);
			}
		}

		for line in lines {
		    let line = try!(line);
		    let values = line.split(self.delimiter);

		    for (i,val) in values.enumerate() {

				// Unwrap and panic for now.
				// Should handle more carefully in future.
				let val = f64::from_str(val).unwrap();
				table.data_cols[i].data.push(val);
			}
		}

		Ok(table)
	}
}<commit_msg>rustfmt<commit_after>use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::str::FromStr;
use datatable::*;

pub struct Loader<'a> {
    pub file: &'a str,
    pub delimiter: char,
}

impl<'a> Loader<'a> {
    /// Load the file from the loader with given delimiter.
    ///
    /// Pretty rudimentary with poor error handling.
    pub fn load_file(self) -> Result<DataTable, io::Error> {
        let f = try!(File::open(self.file));
        let reader = BufReader::new(f);

        let mut table = DataTable::empty();

        // Should handle header here

        let mut lines = reader.lines();

        if let Some(line) = lines.next() {
            let line = try!(line);
            let values = line.split(self.delimiter);

            for val in values {
                let mut column = DataCols::<f64>::empty();
                // Unwrap and panic for now.
                // Should handle more carefully in future.
                column.data.push(f64::from_str(val).unwrap());

                table.data_cols.push(column);
            }
        }

        for line in lines {
            let line = try!(line);
            let values = line.split(self.delimiter);

            for (i, val) in values.enumerate() {

                // Unwrap and panic for now.
                // Should handle more carefully in future.
                let val = f64::from_str(val).unwrap();
                table.data_cols[i].data.push(val);
            }
        }

        Ok(table)
    }
}

pub fn load_file(file: &str) -> DataTable {
    let loader = Loader {
        file: file,
        delimiter: ',',
    };

    loader.load_file().unwrap()

}
<|endoftext|>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/// A metric for calculating indices in `Rope`s based on Unicode graphemes.
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Grapheme(pub usize);
impl Default for Grapheme {
    #[inline] fn default() -> Self { Grapheme(0) }
}
impl convert::From<usize> for Grapheme {
    #[inline] fn from(u: usize) -> Self { Grapheme(u) }
}
impl convert::Into<usize> for Grapheme {
    #[inline] fn into(self) -> usize { self.0 }
}
impl Add<usize> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Grapheme(self.0 + rhs) }
}
impl Add<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Grapheme(self.0 + rhs.0) }
}
impl Monoid for Grapheme { }
impl Sub<usize> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Grapheme(self.0 - rhs) }
}
impl Sub<Grapheme> for Grapheme {
    type Output = Self;
    #[inline] fn sub(self, rhs: Self) -> Self { Grapheme(self.0 - rhs.0) }
}

/// A metric for calculating indices in `Rope`s based on line numbering.
#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line(pub usize);
impl Default for Line {
    #[inline] fn default() -> Self { Line(0) }
}
impl Add<Line> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: Self) -> Self { Line(self.0 + rhs.0) }
}
impl Sub<Line> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: Self) -> Self { Line(self.0 - rhs.0) }
}
impl convert::From<usize> for Line {
    #[inline] fn from(u: usize) -> Self { Line(u) }
}
impl convert::Into<usize> for Line {
    #[inline] fn into(self) -> usize { self.0 }
}
impl Monoid for Line { }
impl Add<usize> for Line {
    type Output = Self;
    #[inline] fn add(self, rhs: usize) -> Self { Line(self.0 + rhs) }
}
impl Sub<usize> for Line {
    type Output = Self;
    #[inline] fn sub(self, rhs: usize) -> Self { Line(self.0 - rhs) }
}

impl Monoid for usize { }
<|endoftext|>


<commit_before><commit_msg>[Auto] lib/domain/todo: Fix Clippy warnings<commit_after><|endoftext|>


<commit_before>use super::ValidatorRecord;

#[derive(Debug, Clone, PartialEq)]
pub struct ChainConfig {
    // Old, potentially outdated constants
    pub cycle_length: u8,
    pub deposit_size_gwei: u64,
    pub shard_count: u16,
    pub min_committee_size: u64,
    pub max_validator_churn_quotient: u64,
    pub genesis_time: u64,
    pub slot_duration_millis: u64,
    pub initial_validators: Vec<ValidatorRecord>,

    // New constants
    pub epoch_length: u64,
    pub min_attestation_inclusion_delay: u64,
}

/*
 * Presently this is just some arbitrary time in Sept 2018.
 */
const TEST_GENESIS_TIME: u64 = 1_537_488_655;

impl ChainConfig {
    pub fn standard() -> Self {
        Self {
            cycle_length: 64,
            deposit_size_gwei: 32 * (10 ^ 9),
            shard_count: 1024,
            min_committee_size: 128,
            max_validator_churn_quotient: 32,
            genesis_time: TEST_GENESIS_TIME,
            slot_duration_millis: 16 * 1000,
            initial_validators: vec![],

            // New
            epoch_length: 64,
            min_attestation_inclusion_delay: 4,
        }
    }

    pub fn validate(&self) -> bool {
        // criteria that ensure the config is valid

        // shard_count / cycle_length > 0 otherwise validator delegation
        // will fail.
        if self.shard_count / u16::from(self.cycle_length) == 0 {
            return false;
        }

        true
    }

    #[cfg(test)]
    pub fn super_fast_tests() -> Self {
        Self {
            cycle_length: 2,
            deposit_size_gwei: 32 * (10 ^ 9),
            shard_count: 2,
            min_committee_size: 2,
            max_validator_churn_quotient: 32,
            genesis_time: TEST_GENESIS_TIME, // arbitrary
            slot_duration_millis: 16 * 1000,
            initial_validators: vec![],

            // New constants
            epoch_length: 64,
            min_attestation_inclusion_delay: 4,
        }
    }
}
<commit_msg>removed chanin_config.rs<commit_after><|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use msg::constellation_msg::{Key, CONTROL};
use script::textinput::{TextInput, Selection, Lines, DeleteDir};
use script::clipboard_provider::DummyClipboardContext;
use std::borrow::ToOwned;

#[test]
fn test_textinput_delete_char() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.delete_char(DeleteDir::Backward);
    assert_eq!(textinput.get_content(), "acdefg");

    textinput.delete_char(DeleteDir::Forward);
    assert_eq!(textinput.get_content(), "adefg");

    textinput.adjust_horizontal(2, Selection::Selected);
    textinput.delete_char(DeleteDir::Forward);
    assert_eq!(textinput.get_content(), "afg");
}

#[test]
fn test_textinput_insert_char() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.insert_char('a');
    assert_eq!(textinput.get_content(), "abacdefg");

    textinput.adjust_horizontal(2, Selection::Selected);
    textinput.insert_char('b');
    assert_eq!(textinput.get_content(), "ababefg");
}

#[test]
fn test_textinput_get_sorted_selection() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.adjust_horizontal(2, Selection::Selected);
    let (begin, end) = textinput.get_sorted_selection();
    assert_eq!(begin.index, 2);
    assert_eq!(end.index, 4);

    textinput.clear_selection();

    textinput.adjust_horizontal(-2, Selection::Selected);
    let (begin, end) = textinput.get_sorted_selection();
    assert_eq!(begin.index, 2);
    assert_eq!(end.index, 4);
}

#[test]
fn test_textinput_replace_selection() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.adjust_horizontal(2, Selection::Selected);

    textinput.replace_selection("xyz".to_owned());
    assert_eq!(textinput.get_content(), "abxyzefg");
}

#[test]
fn test_textinput_current_line_length() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(textinput.current_line_length(), 3);

    textinput.adjust_vertical(1, Selection::NotSelected);
    assert_eq!(textinput.current_line_length(), 2);

    textinput.adjust_vertical(1, Selection::NotSelected);
    assert_eq!(textinput.current_line_length(), 1);
}

#[test]
fn test_textinput_adjust_vertical() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(3, Selection::NotSelected);
    textinput.adjust_vertical(1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 2);

    textinput.adjust_vertical(-1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 2);

    textinput.adjust_vertical(2, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 2);
    assert_eq!(textinput.edit_point.index, 1);
}

#[test]
fn test_textinput_adjust_horizontal() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(4, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 0);

    textinput.adjust_horizontal(1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 1);

    textinput.adjust_horizontal(2, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 2);
    assert_eq!(textinput.edit_point.index, 0);

    textinput.adjust_horizontal(-1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 2);
}

#[test]
fn test_textinput_handle_return() {
    let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned(), DummyClipboardContext::new(""));
    single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
    single_line_textinput.handle_return();
    assert_eq!(single_line_textinput.get_content(), "abcdef");

    let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned(), DummyClipboardContext::new(""));
    multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
    multi_line_textinput.handle_return();
    assert_eq!(multi_line_textinput.get_content(), "abc\ndef");
}

#[test]
fn test_textinput_select_all() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 0);

    textinput.select_all();
    assert_eq!(textinput.edit_point.line, 2);
    assert_eq!(textinput.edit_point.index, 1);
}

#[test]
fn test_textinput_get_content() {
    let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(single_line_textinput.get_content(), "abcdefg");

    let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf");
}

#[test]
fn test_textinput_set_content() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(textinput.get_content(), "abc\nde\nf");

    textinput.set_content("abc\nf".to_owned());
    assert_eq!(textinput.get_content(), "abc\nf");

    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 0);
    textinput.adjust_horizontal(3, Selection::Selected);
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 3);
    textinput.set_content("de".to_owned());
    assert_eq!(textinput.get_content(), "de");
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 2);
}

#[test]
fn test_clipboard_paste() {
    let mut textinput = TextInput::new(Lines::Single, "defg".to_owned(), DummyClipboardContext::new("abc"));
    assert_eq!(textinput.get_content(), "defg");
    assert_eq!(textinput.edit_point.index, 0);
    textinput.handle_keydown_aux(Key::V, CONTROL);
    assert_eq!(textinput.get_content(), "abcdefg");
}
<commit_msg>Fix test_clipboard_paste to pass on Mac OS.<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use msg::constellation_msg::{Key, KeyModifiers};

#[cfg(target_os="macos")]
use msg::constellation_msg::SUPER;
#[cfg(not(target_os="macos"))]
use msg::constellation_msg::CONTROL;

use script::textinput::{TextInput, Selection, Lines, DeleteDir};
use script::clipboard_provider::DummyClipboardContext;
use std::borrow::ToOwned;

#[test]
fn test_textinput_delete_char() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.delete_char(DeleteDir::Backward);
    assert_eq!(textinput.get_content(), "acdefg");

    textinput.delete_char(DeleteDir::Forward);
    assert_eq!(textinput.get_content(), "adefg");

    textinput.adjust_horizontal(2, Selection::Selected);
    textinput.delete_char(DeleteDir::Forward);
    assert_eq!(textinput.get_content(), "afg");
}

#[test]
fn test_textinput_insert_char() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.insert_char('a');
    assert_eq!(textinput.get_content(), "abacdefg");

    textinput.adjust_horizontal(2, Selection::Selected);
    textinput.insert_char('b');
    assert_eq!(textinput.get_content(), "ababefg");
}

#[test]
fn test_textinput_get_sorted_selection() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.adjust_horizontal(2, Selection::Selected);
    let (begin, end) = textinput.get_sorted_selection();
    assert_eq!(begin.index, 2);
    assert_eq!(end.index, 4);

    textinput.clear_selection();

    textinput.adjust_horizontal(-2, Selection::Selected);
    let (begin, end) = textinput.get_sorted_selection();
    assert_eq!(begin.index, 2);
    assert_eq!(end.index, 4);
}

#[test]
fn test_textinput_replace_selection() {
    let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(2, Selection::NotSelected);
    textinput.adjust_horizontal(2, Selection::Selected);

    textinput.replace_selection("xyz".to_owned());
    assert_eq!(textinput.get_content(), "abxyzefg");
}

#[test]
fn test_textinput_current_line_length() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(textinput.current_line_length(), 3);

    textinput.adjust_vertical(1, Selection::NotSelected);
    assert_eq!(textinput.current_line_length(), 2);

    textinput.adjust_vertical(1, Selection::NotSelected);
    assert_eq!(textinput.current_line_length(), 1);
}

#[test]
fn test_textinput_adjust_vertical() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(3, Selection::NotSelected);
    textinput.adjust_vertical(1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 2);

    textinput.adjust_vertical(-1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 2);

    textinput.adjust_vertical(2, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 2);
    assert_eq!(textinput.edit_point.index, 1);
}

#[test]
fn test_textinput_adjust_horizontal() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    textinput.adjust_horizontal(4, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 0);

    textinput.adjust_horizontal(1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 1);

    textinput.adjust_horizontal(2, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 2);
    assert_eq!(textinput.edit_point.index, 0);

    textinput.adjust_horizontal(-1, Selection::NotSelected);
    assert_eq!(textinput.edit_point.line, 1);
    assert_eq!(textinput.edit_point.index, 2);
}

#[test]
fn test_textinput_handle_return() {
    let mut single_line_textinput = TextInput::new(Lines::Single, "abcdef".to_owned(), DummyClipboardContext::new(""));
    single_line_textinput.adjust_horizontal(3, Selection::NotSelected);
    single_line_textinput.handle_return();
    assert_eq!(single_line_textinput.get_content(), "abcdef");

    let mut multi_line_textinput = TextInput::new(Lines::Multiple, "abcdef".to_owned(), DummyClipboardContext::new(""));
    multi_line_textinput.adjust_horizontal(3, Selection::NotSelected);
    multi_line_textinput.handle_return();
    assert_eq!(multi_line_textinput.get_content(), "abc\ndef");
}

#[test]
fn test_textinput_select_all() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 0);

    textinput.select_all();
    assert_eq!(textinput.edit_point.line, 2);
    assert_eq!(textinput.edit_point.index, 1);
}

#[test]
fn test_textinput_get_content() {
    let single_line_textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(single_line_textinput.get_content(), "abcdefg");

    let multi_line_textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(multi_line_textinput.get_content(), "abc\nde\nf");
}

#[test]
fn test_textinput_set_content() {
    let mut textinput = TextInput::new(Lines::Multiple, "abc\nde\nf".to_owned(), DummyClipboardContext::new(""));
    assert_eq!(textinput.get_content(), "abc\nde\nf");

    textinput.set_content("abc\nf".to_owned());
    assert_eq!(textinput.get_content(), "abc\nf");

    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 0);
    textinput.adjust_horizontal(3, Selection::Selected);
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 3);
    textinput.set_content("de".to_owned());
    assert_eq!(textinput.get_content(), "de");
    assert_eq!(textinput.edit_point.line, 0);
    assert_eq!(textinput.edit_point.index, 2);
}

#[test]
fn test_clipboard_paste() {
    #[cfg(target_os="macos")]
    const MODIFIERS: KeyModifiers = SUPER;
    #[cfg(not(target_os="macos"))]
    const MODIFIERS: KeyModifiers = CONTROL;

    let mut textinput = TextInput::new(Lines::Single, "defg".to_owned(), DummyClipboardContext::new("abc"));
    assert_eq!(textinput.get_content(), "defg");
    assert_eq!(textinput.edit_point.index, 0);
    textinput.handle_keydown_aux(Key::V, MODIFIERS);
    assert_eq!(textinput.get_content(), "abcdefg");
}
<|endoftext|>