<commit_before>#![crate_id = "chroot#1.0.0"]
/*
 * This file is part of the uutils coreutils package.
 *
 * © Vsevolod Velichko <torkvemada@sorokdva.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]
extern crate getopts;
extern crate libc;

use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group};
use libc::funcs::posix88::unistd::{execvp, setuid, setgid};

#[path = "../common/util.rs"] mod util;
#[path = "../common/c_types.rs"] mod c_types;

extern {
    fn chroot(path: *libc::c_char) -> libc::c_int;
    fn setgroups(size: libc::c_int, list: *libc::uid_t) -> libc::c_int;
}

static NAME : &'static str = "chroot";
static VERSION : &'static str = "1.0.0";

#[allow(dead_code)]
fn main () { std::os::set_exit_status(uumain(std::os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0);

    let options = [
        optopt("u", "user", "User (ID or name) to switch before running the program", "USER"),
        optopt("g", "group", "Group (ID or name) to switch to", "GROUP"),
        optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2…"),
        optopt("", "userspec", "Colon-separated user and group to switch to. \
                                Same as -u USER -g GROUP. \
                                Userspec has higher preference than -u and/or -g", "USER:GROUP"),
        optflag("h", "help", "Show help"),
        optflag("V", "version", "Show program's version")
    ];

    let opts = match getopts(args.tail(), options) {
        Ok(m) => {m}
        Err(f) => {
            println!("{}", f);
            help_menu(program.as_slice(), options);
            return 1
        }
    };

    if opts.opt_present("V") { version(); return 0 }
    if opts.opt_present("h") { help_menu(program.as_slice(), options); return 0 }

    if opts.free.len() == 0 {
        println!("Missing operand: NEWROOT");
        println!("Try `{:s} --help` for more information.", program.as_slice());
        return 1
    }

    let defaultShell : &'static str = "/bin/sh";
    let defaultOption : &'static str = "-i";
    let userShell = std::os::getenv("SHELL");

    let newroot = Path::new(opts.free.get(0).as_slice());
    if !newroot.is_dir() {
        crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
    }

    let command : Vec<&str> = match opts.free.len() {
        1 => {
            let shell : &str = match userShell {
                None => {defaultShell}
                Some(ref s) => {s.as_slice()}
            };
            vec!(shell, defaultOption)
        }
        _ => { opts.free.slice(1, opts.free.len()).iter().map(|x| x.as_slice()).collect() }
    };

    set_context(&newroot, &opts);

    unsafe {
        let executable = command.get(0).as_slice().to_c_str().unwrap();
        let mut commandParts : Vec<*i8> = command.iter().map(|x| x.to_c_str().unwrap()).collect();
        commandParts.push(std::ptr::null());
        execvp(executable as *libc::c_char, commandParts.as_ptr() as **libc::c_char) as int
    }
}

fn set_context(root: &Path, options: &getopts::Matches) {
    let userspecStr = options.opt_str("userspec");
    let userStr = options.opt_str("user").unwrap_or_default();
    let groupStr = options.opt_str("group").unwrap_or_default();
    let groupsStr = options.opt_str("groups").unwrap_or_default();
    let userspec = match userspecStr {
        Some(ref u) => {
            let s : Vec<&str> = u.as_slice().split(':').collect();
            if s.len() != 2 {
                crash!(1, "invalid userspec: `{:s}`", u.as_slice())
            };
            s
        }
        None => { Vec::new() }
    };
    let user = if userspec.is_empty() { userStr.as_slice() } else { userspec.get(0).as_slice() };
    let group = if userspec.is_empty() { groupStr.as_slice() } else { userspec.get(1).as_slice() };

    enter_chroot(root);

    set_groups(groupsStr.as_slice());
    set_main_group(group);
    set_user(user);
}

fn enter_chroot(root: &Path) {
    let rootStr = root.display();
    if !std::os::change_dir(root) {
        crash!(1, "cannot chdir to {}", rootStr)
    };
    let err = unsafe {
        chroot(".".to_c_str().unwrap() as *libc::c_char)
    };
    if err != 0 {
        crash!(1, "cannot chroot to {}: {:s}", rootStr, strerror(err).as_slice())
    };
}

fn set_main_group(group: &str) {
    if !group.is_empty() {
        let group_id = match get_group(group) {
            None => { crash!(1, "no such group: {}", group) }
            Some(g) => g.gr_gid
        };
        let err = unsafe { setgid(group_id) };
        if err != 0 {
            crash!(1, "cannot set gid to {:u}: {:s}", group_id, strerror(err).as_slice())
        }
    }
}

fn set_groups(groups: &str) {
    if !groups.is_empty() {
        let groupsVec : Vec<libc::uid_t> = FromIterator::from_iter(
            groups.split(',').map(
                |x| match get_group(x) {
                    None => { crash!(1, "no such group: {}", x) }
                    Some(g) => { g.gr_gid }
                })
            );
        let err = unsafe {
            setgroups(groupsVec.len() as libc::c_int,
                      groupsVec.as_slice().as_ptr() as *libc::uid_t)
        };
        if err != 0 {
            crash!(1, "cannot set groups: {:s}", strerror(err).as_slice())
        }
    }
}

fn set_user(user: &str) {
    if !user.is_empty() {
        let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
        let err = unsafe { setuid(user_id as libc::uid_t) };
        if err != 0 {
            crash!(1, "cannot set user to {:s}: {:s}", user, strerror(err).as_slice())
        }
    }
}

fn strerror(errno: i32) -> String {
    unsafe {
        let err = libc::funcs::c95::string::strerror(errno);
        std::str::raw::from_c_str(err)
    }
}

fn version() {
    println!("{} v{}", NAME, VERSION)
}

fn help_menu(program: &str, options: &[getopts::OptGroup]) {
    version();
    println!("Usage:");
    println!("  {:s} [OPTION]… NEWROOT [COMMAND [ARG]…]", program);
    println!("");
    print!("{:s}", usage(
            "Run COMMAND with root directory set to NEWROOT.\n\
             If COMMAND is not specified, it defaults to '${SHELL} -i'. \
             If ${SHELL} is not set, /bin/sh is used.", options))
}
<commit_msg>Code style fixes<commit_after>#![crate_id = "chroot#1.0.0"]
/*
 * This file is part of the uutils coreutils package.
 *
 * © Vsevolod Velichko <torkvemada@sorokdva.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]
extern crate getopts;
extern crate libc;

use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group};
use libc::funcs::posix88::unistd::{execvp, setuid, setgid};

#[path = "../common/util.rs"] mod util;
#[path = "../common/c_types.rs"] mod c_types;

extern {
    fn chroot(path: *libc::c_char) -> libc::c_int;
    fn setgroups(size: libc::c_int, list: *libc::uid_t) -> libc::c_int;
}

static NAME: &'static str = "chroot";
static VERSION: &'static str = "1.0.0";

#[allow(dead_code)]
fn main () { std::os::set_exit_status(uumain(std::os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0);

    let options = [
        optopt("u", "user", "User (ID or name) to switch before running the program", "USER"),
        optopt("g", "group", "Group (ID or name) to switch to", "GROUP"),
        optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2…"),
        optopt("", "userspec", "Colon-separated user and group to switch to. \
                                Same as -u USER -g GROUP. \
                                Userspec has higher preference than -u and/or -g", "USER:GROUP"),
        optflag("h", "help", "Show help"),
        optflag("V", "version", "Show program's version")
    ];

    let opts = match getopts(args.tail(), options) {
        Ok(m) => {m}
        Err(f) => {
            println!("{}", f);
            help_menu(program.as_slice(), options);
            return 1
        }
    };

    if opts.opt_present("V") { version(); return 0 }
    if opts.opt_present("h") { help_menu(program.as_slice(), options); return 0 }

    if opts.free.len() == 0 {
        println!("Missing operand: NEWROOT");
        println!("Try `{:s} --help` for more information.", program.as_slice());
        return 1
    }

    let defaultShell: &'static str = "/bin/sh";
    let defaultOption: &'static str = "-i";
    let userShell = std::os::getenv("SHELL");

    let newroot = Path::new(opts.free.get(0).as_slice());
    if !newroot.is_dir() {
        crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
    }

    let command: Vec<&str> = match opts.free.len() {
        1 => {
            let shell: &str = match userShell {
                None => {defaultShell}
                Some(ref s) => {s.as_slice()}
            };
            vec!(shell, defaultOption)
        }
        _ => { opts.free.slice(1, opts.free.len()).iter().map(|x| x.as_slice()).collect() }
    };

    set_context(&newroot, &opts);

    unsafe {
        let executable = command.get(0).as_slice().to_c_str().unwrap();
        let mut commandParts: Vec<*i8> = command.iter().map(|x| x.to_c_str().unwrap()).collect();
        commandParts.push(std::ptr::null());
        execvp(executable as *libc::c_char, commandParts.as_ptr() as **libc::c_char) as int
    }
}

fn set_context(root: &Path, options: &getopts::Matches) {
    let userspecStr = options.opt_str("userspec");
    let userStr = options.opt_str("user").unwrap_or_default();
    let groupStr = options.opt_str("group").unwrap_or_default();
    let groupsStr = options.opt_str("groups").unwrap_or_default();
    let userspec = match userspecStr {
        Some(ref u) => {
            let s: Vec<&str> = u.as_slice().split(':').collect();
            if s.len() != 2 {
                crash!(1, "invalid userspec: `{:s}`", u.as_slice())
            };
            s
        }
        None => { Vec::new() }
    };
    let user = if userspec.is_empty() { userStr.as_slice() } else { userspec.get(0).as_slice() };
    let group = if userspec.is_empty() { groupStr.as_slice() } else { userspec.get(1).as_slice() };

    enter_chroot(root);

    set_groups(groupsStr.as_slice());
    set_main_group(group);
    set_user(user);
}

fn enter_chroot(root: &Path) {
    let rootStr = root.display();
    if !std::os::change_dir(root) {
        crash!(1, "cannot chdir to {}", rootStr)
    };
    let err = unsafe {
        chroot(".".to_c_str().unwrap() as *libc::c_char)
    };
    if err != 0 {
        crash!(1, "cannot chroot to {}: {:s}", rootStr, strerror(err).as_slice())
    };
}

fn set_main_group(group: &str) {
    if !group.is_empty() {
        let group_id = match get_group(group) {
            None => { crash!(1, "no such group: {}", group) }
            Some(g) => g.gr_gid
        };
        let err = unsafe { setgid(group_id) };
        if err != 0 {
            crash!(1, "cannot set gid to {:u}: {:s}", group_id, strerror(err).as_slice())
        }
    }
}

fn set_groups(groups: &str) {
    if !groups.is_empty() {
        let groupsVec: Vec<libc::uid_t> = FromIterator::from_iter(
            groups.split(',').map(
                |x| match get_group(x) {
                    None => { crash!(1, "no such group: {}", x) }
                    Some(g) => { g.gr_gid }
                })
            );
        let err = unsafe {
            setgroups(groupsVec.len() as libc::c_int,
                      groupsVec.as_slice().as_ptr() as *libc::uid_t)
        };
        if err != 0 {
            crash!(1, "cannot set groups: {:s}", strerror(err).as_slice())
        }
    }
}

fn set_user(user: &str) {
    if !user.is_empty() {
        let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
        let err = unsafe { setuid(user_id as libc::uid_t) };
        if err != 0 {
            crash!(1, "cannot set user to {:s}: {:s}", user, strerror(err).as_slice())
        }
    }
}

fn strerror(errno: i32) -> String {
    unsafe {
        let err = libc::funcs::c95::string::strerror(errno);
        std::str::raw::from_c_str(err)
    }
}

fn version() {
    println!("{} v{}", NAME, VERSION)
}

fn help_menu(program: &str, options: &[getopts::OptGroup]) {
    version();
    println!("Usage:");
    println!("  {:s} [OPTION]… NEWROOT [COMMAND [ARG]…]", program);
    println!("");
    print!("{:s}", usage(
            "Run COMMAND with root directory set to NEWROOT.\n\
             If COMMAND is not specified, it defaults to '${SHELL} -i'. \
             If ${SHELL} is not set, /bin/sh is used.", options))
}
<|endoftext|>


<commit_before><commit_msg>add testcases for r2::Rect<commit_after><|endoftext|>


<commit_before>use crate::tokenizer;
use crate::{
    constants::*,
    token_collector::{Style, StyledToken, TokenCollector},
};
use diffus::{
    edit::{self, collection},
    Diffable,
};

/// Like format!(), but faster for our special case
fn format_simple_line(old_new: &str, plus_minus: char, contents: &str) -> String {
    let mut line = String::with_capacity(old_new.len() + 1 + contents.len() + NORMAL.len());
    line.push_str(old_new);
    line.push(plus_minus);
    line.push_str(contents);
    line.push_str(NORMAL);
    return line;
}

/// Format old and new lines in OLD and NEW colors.
///
/// No intra-line refinement.
///
/// Returns one old and one new line array.
#[must_use]
fn simple_format(old_text: &str, new_text: &str) -> (Vec<String>, Vec<String>) {
    let mut old_lines: Vec<String> = Vec::new();
    let mut new_lines: Vec<String> = Vec::new();

    for old_line in old_text.lines() {
        // Use a specialized line formatter since this code is in a hot path
        old_lines.push(format_simple_line(OLD, '-', old_line));
    }
    if (!old_text.is_empty()) && !old_text.ends_with('\n') {
        old_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    for add_line in new_text.lines() {
        // Use a specialized line formatter since this code is in a hot path
        new_lines.push(format_simple_line(NEW, '+', add_line));
    }
    if (!new_text.is_empty()) && !new_text.ends_with('\n') {
        new_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return (old_lines, new_lines);
}

#[must_use]
fn concat(mut a: Vec<String>, mut b: Vec<String>) -> Vec<String> {
    let mut merged: Vec<String> = Vec::new();
    merged.append(&mut a);
    merged.append(&mut b);
    return merged;
}

/// Returns a vector of ANSI highlighted lines
#[must_use]
pub fn format(old_text: &str, new_text: &str) -> Vec<String> {
    match format_split(old_text, new_text) {
        None => {
            let (old_lines, new_lines) = simple_format(old_text, new_text);
            return concat(old_lines, new_lines);
        }

        Some((old_lines, new_lines)) => {
            return concat(old_lines, new_lines);
        }
    }
}

/// Returns two vectors of ANSI highlighted lines, the old lines and the new
/// lines.
///
/// A return value of None means you should try partial_format() instead.
#[must_use]
fn format_split(old_text: &str, new_text: &str) -> Option<(Vec<String>, Vec<String>)> {
    if old_text.is_empty() || new_text.is_empty() {
        return Some(simple_format(old_text, new_text));
    }

    // FIXME: LCS is O(m * n) complexity, consider returning None here if
    // len(old_text) * len(new_text) is too large.

    // Find diffs between adds and removals
    let mut old_collector = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
    let mut new_collector = TokenCollector::create(StyledToken::new("+".to_string(), Style::New));

    // Tokenize adds and removes before diffing them
    let tokenized_old = tokenizer::tokenize(old_text);
    let tokenized_new = tokenizer::tokenize(new_text);

    let diff = tokenized_old.diff(&tokenized_new);
    match diff {
        edit::Edit::Copy(unchanged) => {
            for token in unchanged {
                old_collector.push(StyledToken::new(token.to_string(), Style::Old));
                new_collector.push(StyledToken::new(token.to_string(), Style::New));
            }
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        collection::Edit::Copy(token) => {
                            old_collector.push(StyledToken::new(token.to_string(), Style::Old));
                            new_collector.push(StyledToken::new(token.to_string(), Style::New));
                        }
                        collection::Edit::Insert(token) => {
                            if *token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                new_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::NewInverse));
                            }
                            new_collector
                                .push(StyledToken::new(token.to_string(), Style::NewInverse));
                        }
                        collection::Edit::Remove(token) => {
                            if *token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                old_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::OldInverse));
                            }
                            old_collector
                                .push(StyledToken::new(token.to_string(), Style::OldInverse));
                        }
                        collection::Edit::Change(_) => unimplemented!("Not implemented, help!"),
                    };
                })
                .for_each(drop);
        }
    }

    let highlighted_old_text = old_collector.render();
    let highlighted_new_text = new_collector.render();

    return Some(to_lines(&highlighted_old_text, &highlighted_new_text));
}

#[must_use]
fn to_lines(old: &str, new: &str) -> (Vec<String>, Vec<String>) {
    let mut old_lines: Vec<String> = Vec::new();
    for highlighted_old_line in old.lines() {
        old_lines.push(highlighted_old_line.to_string());
    }
    if (!old.is_empty()) && !old.ends_with('\n') {
        old_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    let mut new_lines: Vec<String> = Vec::new();
    for highlighted_new_line in new.lines() {
        new_lines.push(highlighted_new_line.to_string());
    }
    if (!new.is_empty()) && !new.ends_with('\n') {
        new_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return (old_lines, new_lines);
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    fn simple_format_merged(old_text: &str, new_text: &str) -> Vec<String> {
        let (old_lines, new_lines) = simple_format(old_text, new_text);

        return concat(old_lines, new_lines);
    }

    #[test]
    fn test_simple_format_adds_and_removes() {
        let empty: Vec<String> = Vec::new();
        assert_eq!(
            simple_format_merged(&"".to_string(), &"".to_string()),
            empty
        );

        // Test adds-only
        assert_eq!(
            simple_format_merged(&"".to_string(), &"a\n".to_string()),
            ["".to_string() + NEW + "+a" + NORMAL]
        );
        assert_eq!(
            simple_format_merged(&"".to_string(), &"a\nb\n".to_string()),
            [
                "".to_string() + NEW + "+a" + NORMAL,
                "".to_string() + NEW + "+b" + NORMAL,
            ]
        );

        // Test removes-only
        assert_eq!(
            simple_format_merged(&"a\n".to_string(), &"".to_string()),
            ["".to_string() + OLD + "-a" + NORMAL]
        );
        assert_eq!(
            simple_format_merged(&"a\nb\n".to_string(), &"".to_string()),
            [
                "".to_string() + OLD + "-a" + NORMAL,
                "".to_string() + OLD + "-b" + NORMAL,
            ]
        );
    }

    #[test]
    fn test_quote_change() {
        let result = format(&"<quotes>\n".to_string(), &"[quotes]\n".to_string());
        assert_eq!(
            result,
            [
                format!(
                    "{}-{}<{}quotes{}>{}",
                    OLD, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
                format!(
                    "{}+{}[{}quotes{}]{}",
                    NEW, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
            ]
        )
    }

    #[test]
    fn test_almost_empty_changes() {
        let result = format(&"x\n".to_string(), &"".to_string());
        assert_eq!(result, [format!("{}-x{}", OLD, NORMAL),]);

        let result = format(&"".to_string(), &"x\n".to_string());
        assert_eq!(result, [format!("{}+x{}", NEW, NORMAL),]);
    }

    #[test]
    fn test_is_large_byte_count_change() {
        assert_eq!(is_large_byte_count_change("", ""), false);

        assert_eq!(
            is_large_byte_count_change("", &"x".repeat(SMALL_COUNT_CHANGE)),
            false
        );
        assert_eq!(
            is_large_byte_count_change("", &"x".repeat(SMALL_COUNT_CHANGE + 1)),
            true
        );

        // Verify that doubling the length counts as large
        let base_len = SMALL_COUNT_CHANGE * 2;
        let double_len = base_len * 2;
        let almost_double_len = double_len - 1;
        assert_eq!(
            is_large_byte_count_change(&"x".repeat(base_len), &"y".repeat(almost_double_len)),
            false
        );
        assert_eq!(
            is_large_byte_count_change(&"x".repeat(base_len), &"y".repeat(double_len)),
            true
        );
    }

    #[test]
    fn test_extract_trailing_lines() {
        assert_eq!(
            extract_trailing_lines(2, "apa\nbepa\ncepa\n"),
            "bepa\ncepa\n"
        )
    }
}
<commit_msg>Make test suite compile again<commit_after>use crate::tokenizer;
use crate::{
    constants::*,
    token_collector::{Style, StyledToken, TokenCollector},
};
use diffus::{
    edit::{self, collection},
    Diffable,
};

/// Like format!(), but faster for our special case
fn format_simple_line(old_new: &str, plus_minus: char, contents: &str) -> String {
    let mut line = String::with_capacity(old_new.len() + 1 + contents.len() + NORMAL.len());
    line.push_str(old_new);
    line.push(plus_minus);
    line.push_str(contents);
    line.push_str(NORMAL);
    return line;
}

/// Format old and new lines in OLD and NEW colors.
///
/// No intra-line refinement.
///
/// Returns one old and one new line array.
#[must_use]
fn simple_format(old_text: &str, new_text: &str) -> (Vec<String>, Vec<String>) {
    let mut old_lines: Vec<String> = Vec::new();
    let mut new_lines: Vec<String> = Vec::new();

    for old_line in old_text.lines() {
        // Use a specialized line formatter since this code is in a hot path
        old_lines.push(format_simple_line(OLD, '-', old_line));
    }
    if (!old_text.is_empty()) && !old_text.ends_with('\n') {
        old_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    for add_line in new_text.lines() {
        // Use a specialized line formatter since this code is in a hot path
        new_lines.push(format_simple_line(NEW, '+', add_line));
    }
    if (!new_text.is_empty()) && !new_text.ends_with('\n') {
        new_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return (old_lines, new_lines);
}

#[must_use]
fn concat(mut a: Vec<String>, mut b: Vec<String>) -> Vec<String> {
    let mut merged: Vec<String> = Vec::new();
    merged.append(&mut a);
    merged.append(&mut b);
    return merged;
}

/// Returns a vector of ANSI highlighted lines
#[must_use]
pub fn format(old_text: &str, new_text: &str) -> Vec<String> {
    match format_split(old_text, new_text) {
        None => {
            let (old_lines, new_lines) = simple_format(old_text, new_text);
            return concat(old_lines, new_lines);
        }

        Some((old_lines, new_lines)) => {
            return concat(old_lines, new_lines);
        }
    }
}

/// Returns two vectors of ANSI highlighted lines, the old lines and the new
/// lines.
///
/// A return value of None means you should try partial_format() instead.
#[must_use]
fn format_split(old_text: &str, new_text: &str) -> Option<(Vec<String>, Vec<String>)> {
    if old_text.is_empty() || new_text.is_empty() {
        return Some(simple_format(old_text, new_text));
    }

    // FIXME: LCS is O(m * n) complexity, consider returning None here if
    // len(old_text) * len(new_text) is too large.

    // Find diffs between adds and removals
    let mut old_collector = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
    let mut new_collector = TokenCollector::create(StyledToken::new("+".to_string(), Style::New));

    // Tokenize adds and removes before diffing them
    let tokenized_old = tokenizer::tokenize(old_text);
    let tokenized_new = tokenizer::tokenize(new_text);

    let diff = tokenized_old.diff(&tokenized_new);
    match diff {
        edit::Edit::Copy(unchanged) => {
            for token in unchanged {
                old_collector.push(StyledToken::new(token.to_string(), Style::Old));
                new_collector.push(StyledToken::new(token.to_string(), Style::New));
            }
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        collection::Edit::Copy(token) => {
                            old_collector.push(StyledToken::new(token.to_string(), Style::Old));
                            new_collector.push(StyledToken::new(token.to_string(), Style::New));
                        }
                        collection::Edit::Insert(token) => {
                            if *token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                new_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::NewInverse));
                            }
                            new_collector
                                .push(StyledToken::new(token.to_string(), Style::NewInverse));
                        }
                        collection::Edit::Remove(token) => {
                            if *token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                old_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::OldInverse));
                            }
                            old_collector
                                .push(StyledToken::new(token.to_string(), Style::OldInverse));
                        }
                        collection::Edit::Change(_) => unimplemented!("Not implemented, help!"),
                    };
                })
                .for_each(drop);
        }
    }

    let highlighted_old_text = old_collector.render();
    let highlighted_new_text = new_collector.render();

    return Some(to_lines(&highlighted_old_text, &highlighted_new_text));
}

#[must_use]
fn to_lines(old: &str, new: &str) -> (Vec<String>, Vec<String>) {
    let mut old_lines: Vec<String> = Vec::new();
    for highlighted_old_line in old.lines() {
        old_lines.push(highlighted_old_line.to_string());
    }
    if (!old.is_empty()) && !old.ends_with('\n') {
        old_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    let mut new_lines: Vec<String> = Vec::new();
    for highlighted_new_line in new.lines() {
        new_lines.push(highlighted_new_line.to_string());
    }
    if (!new.is_empty()) && !new.ends_with('\n') {
        new_lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return (old_lines, new_lines);
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    fn simple_format_merged(old_text: &str, new_text: &str) -> Vec<String> {
        let (old_lines, new_lines) = simple_format(old_text, new_text);

        return concat(old_lines, new_lines);
    }

    #[test]
    fn test_simple_format_adds_and_removes() {
        let empty: Vec<String> = Vec::new();
        assert_eq!(
            simple_format_merged(&"".to_string(), &"".to_string()),
            empty
        );

        // Test adds-only
        assert_eq!(
            simple_format_merged(&"".to_string(), &"a\n".to_string()),
            ["".to_string() + NEW + "+a" + NORMAL]
        );
        assert_eq!(
            simple_format_merged(&"".to_string(), &"a\nb\n".to_string()),
            [
                "".to_string() + NEW + "+a" + NORMAL,
                "".to_string() + NEW + "+b" + NORMAL,
            ]
        );

        // Test removes-only
        assert_eq!(
            simple_format_merged(&"a\n".to_string(), &"".to_string()),
            ["".to_string() + OLD + "-a" + NORMAL]
        );
        assert_eq!(
            simple_format_merged(&"a\nb\n".to_string(), &"".to_string()),
            [
                "".to_string() + OLD + "-a" + NORMAL,
                "".to_string() + OLD + "-b" + NORMAL,
            ]
        );
    }

    #[test]
    fn test_quote_change() {
        let result = format(&"<quotes>\n".to_string(), &"[quotes]\n".to_string());
        assert_eq!(
            result,
            [
                format!(
                    "{}-{}<{}quotes{}>{}",
                    OLD, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
                format!(
                    "{}+{}[{}quotes{}]{}",
                    NEW, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
            ]
        )
    }

    #[test]
    fn test_almost_empty_changes() {
        let result = format(&"x\n".to_string(), &"".to_string());
        assert_eq!(result, [format!("{}-x{}", OLD, NORMAL),]);

        let result = format(&"".to_string(), &"x\n".to_string());
        assert_eq!(result, [format!("{}+x{}", NEW, NORMAL),]);
    }
}
<|endoftext|>


<commit_before>pub mod builtins;
pub mod utils;
pub mod read_line;
pub mod exec;

use std::env;
use std::path::{Path, PathBuf};
use std::fmt;
use std::io;
use std::io::Write;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Clone)]
pub struct State {
    cwd: PathBuf,
    variables: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
    exit_status: i32,
}

impl fmt::Debug for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "State {{
\tcwd: {},
\tvariables: {:?},
\taliases: {:?},
\targv: {:?}
\targc: {}
\texit_status: {}
}}
",
               self.cwd.display(),
               self.variables,
               self.aliases,
               self.argv,
               self.argc,
               self.exit_status)
    }
}

impl State {
    pub fn new(cwd: String) -> State {
        let mut vars = HashMap::new();
        vars.insert("PATH".to_string(),
                    "/usr/bin;/usr/local/bin;/bin;/sbin".to_string());

        State {
            cwd: utils::make_absolute(PathBuf::from(cwd)).unwrap(),
            variables: vars.clone(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
            exit_status: 0,
        }
    }

    pub fn default() -> State {
        match env::current_dir() {
            Ok(cwd) => {
                let mut vars = HashMap::new();
                vars.insert("PATH".to_string(),
                            "/usr/bin;/usr/local/bin;/bin;/sbin".to_string());

                State {
                    cwd: cwd,
                    variables: vars.clone(),
                    aliases: HashMap::new(),
                    argv: Vec::new(),
                    argc: 0,
                    exit_status: 0,
                }
            }
            Err(e) => panic!(e),
        }
    }

    pub fn exec_paths(&self) -> Vec<PathBuf> {
        let path = if let Some(s) = self.variables.get("PATH") {
            s.clone()
        } else {
            "".to_string()
        };

        path.split(";")
            .map(|x| Path::new(x).to_path_buf())
            .collect()
    }

    pub fn env<'a>(&'a mut self, key: String, value: String) -> &'a mut State {
        self.variables.insert(key, value);
        self
    }

    pub fn alias<'a>(&'a mut self, alias: String, value: String) -> &'a mut State {
        self.aliases.insert(alias, value);
        self
    }
}

pub fn run(initial_state: State) {
    let mut s = initial_state.clone();
    let mut builtins = builtins::load();
    let i = read_line::Input::from(&s);

    println!("Welcome to rsh! {:?}", s);

    loop {

        let input = i.prompt(format!("{} -> ", s.cwd.display()));

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {} {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s.exit_status = bn(&mut s);
            // prompt for input again.
            continue;
        }

        // else try to run the command
        exec::exec(&s);
    }
}

#[derive(PartialEq)]
enum BuildType {
    None,
    Single,
    Double,
}

struct ParseResult {
    result: Vec<String>,
    completed: bool,
    build_string: String,
    build_type: BuildType,
}

fn parse_args(args: &String) -> Vec<String> {
    if args.len() == 0 {
        return Vec::new();
    }

    let mut parse_result: ParseResult = ParseResult {
        result: Vec::new(),
        completed: false,
        build_string: String::from(""),
        build_type: BuildType::None,
    };

    let mut argstr = args.clone();

    parse_string_into_vec(&argstr, &mut parse_result);

    while !parse_result.completed {
        // prompt for the rest of input
        print!(">");
        io::stdout().flush();
        argstr = String::from("");
        io::stdin().read_line(&mut argstr).unwrap();

        parse_string_into_vec(&argstr, &mut parse_result);
    }

    let result: Vec<String> = parse_result.result
        .into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

fn parse_string_into_vec(string: &String, parse_result: &mut ParseResult) {
    let &mut ParseResult { ref mut build_string,
                           ref mut build_type,
                           ref mut completed,
                           ref mut result } = parse_result;
    let mut iter = string.chars().peekable();

    while let Some(c) = iter.next() {
        match c {
            '\'' => {
                match *build_type {
                    BuildType::Single => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match *build_type {
                    BuildType::Double => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match *build_type {
                    BuildType::None => {
                        result.push(build_string.clone());
                        *build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\n' => {
                match *build_type {
                    BuildType::None => {
                        match iter.peek() {
                            Some(_) => {
                                build_string.push(c);
                            }
                            None => {}
                        }
                    }
                    _ => {
                        build_string.push(c);
                    }
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if *build_type == BuildType::None {
        *completed = true;
        if build_string.len() > 0 {
            result.push(build_string.clone());
        }
    }
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside quotes
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed quotes section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed quotes sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around single quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo 'hello'world"));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around double quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo \"hello\"world"));
        assert_eq!(result, expected);
    }

    // allow double quotes inside single quotes
    {
        let expected = vec!["\"".to_string()];
        let result = parse_args(&String::from("'\"'"));
        assert_eq!(result, expected);
    }

    // allow single quotes inside double quotes
    {
        let expected = vec!["\'".to_string()];
        let result = parse_args(&String::from("\"\'\""));
        assert_eq!(result, expected);
    }

    // handle multiple quote sections in succession
    {
        let expected = vec!["echo".to_string(), "hello world how are you".into()];
        let result = parse_args(&String::from("echo \"hello world\"\' how are you\'"));
        assert_eq!(result, expected);
    }

    // preserve newlines
    {
        let expected = vec!["echo".to_string(), "hello\nworld".into()];
        let result = parse_args(&String::from("echo \"hello\nworld\""));
        assert_eq!(result, expected);
    }

    // remove final newline
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo\n"));
        assert_eq!(result, expected);
    }
}
<commit_msg>path separator is different on unix v windows<commit_after>pub mod builtins;
pub mod utils;
pub mod read_line;
pub mod exec;

use std::env;
use std::path::{Path, PathBuf};
use std::fmt;
use std::io;
use std::io::Write;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

#[derive(Clone)]
pub struct State {
    cwd: PathBuf,
    variables: HashMap<String, String>,
    aliases: HashMap<String, String>,
    argv: Vec<String>,
    argc: usize,
    exit_status: i32,
}

impl fmt::Debug for State {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "State {{
\tcwd: {},
\tvariables: {:?},
\taliases: {:?},
\targv: {:?}
\targc: {}
\texit_status: {}
}}
",
               self.cwd.display(),
               self.variables,
               self.aliases,
               self.argv,
               self.argc,
               self.exit_status)
    }
}

impl State {
    pub fn new(cwd: String) -> State {
        let mut vars = HashMap::new();
        vars.insert("PATH".to_string(),
                    "/usr/bin;/usr/local/bin;/bin;/sbin".to_string());

        State {
            cwd: utils::make_absolute(PathBuf::from(cwd)).unwrap(),
            variables: vars.clone(),
            aliases: HashMap::new(),
            argv: Vec::new(),
            argc: 0,
            exit_status: 0,
        }
    }

    pub fn default() -> State {
        match env::current_dir() {
            Ok(cwd) => {
                let mut vars = HashMap::new();
                vars.insert("PATH".to_string(),
                            "/usr/bin;/usr/local/bin;/bin;/sbin".to_string());

                State {
                    cwd: cwd,
                    variables: vars.clone(),
                    aliases: HashMap::new(),
                    argv: Vec::new(),
                    argc: 0,
                    exit_status: 0,
                }
            }
            Err(e) => panic!(e),
        }
    }

    #[cfg(any(unix))]
    pub fn exec_paths(&self) -> Vec<PathBuf> {
        let path = if let Ok(s) = env::var("PATH") {
            s.clone()
        } else {
            "".to_string()
        };

        path.split(":")
            .map(|x| Path::new(x).to_path_buf())
            .collect()
    }

    #[cfg(windows)]
    pub fn exec_paths(&self) -> Vec<PathBuf> {
        let path = if let Ok(s) = env::var("PATH") {
            s.clone()
        } else {
            "".to_string()
        };

        path.split(";")
            .map(|x| Path::new(x).to_path_buf())
            .collect()
    }

    pub fn env<'a>(&'a mut self, key: String, value: String) -> &'a mut State {
        self.variables.insert(key, value);
        self
    }

    pub fn alias<'a>(&'a mut self, alias: String, value: String) -> &'a mut State {
        self.aliases.insert(alias, value);
        self
    }
}

pub fn run(initial_state: State) {
    let mut s = initial_state.clone();
    let mut builtins = builtins::load();
    let i = read_line::Input::from(&s);

    println!("Welcome to rsh! {:?}", s);

    loop {

        let input = i.prompt(format!("{} -> ", s.cwd.display()));

        s.argv = parse_args(&input);
        s.argc = s.argv.len();

        print!("\n");
        println!("Input: {} {:?}", input, s);

        let first_arg = s.argv.get(0).unwrap().clone();
        if let Entry::Occupied(f) = builtins.entry(String::from(first_arg)) {
            let bn = f.get();
            s.exit_status = bn(&mut s);
            // prompt for input again.
            continue;
        }

        // else try to run the command
        exec::exec(&s);
    }
}

#[derive(PartialEq)]
enum BuildType {
    None,
    Single,
    Double,
}

struct ParseResult {
    result: Vec<String>,
    completed: bool,
    build_string: String,
    build_type: BuildType,
}

fn parse_args(args: &String) -> Vec<String> {
    if args.len() == 0 {
        return Vec::new();
    }

    let mut parse_result: ParseResult = ParseResult {
        result: Vec::new(),
        completed: false,
        build_string: String::from(""),
        build_type: BuildType::None,
    };

    let mut argstr = args.clone();

    parse_string_into_vec(&argstr, &mut parse_result);

    while !parse_result.completed {
        // prompt for the rest of input
        print!(">");
        io::stdout().flush();
        argstr = String::from("");
        io::stdin().read_line(&mut argstr).unwrap();

        parse_string_into_vec(&argstr, &mut parse_result);
    }

    let result: Vec<String> = parse_result.result
        .into_iter()
        .filter(|s| s.len() > 0)
        .collect();

    result
}

fn parse_string_into_vec(string: &String, parse_result: &mut ParseResult) {
    let &mut ParseResult { ref mut build_string,
                           ref mut build_type,
                           ref mut completed,
                           ref mut result } = parse_result;
    let mut iter = string.chars().peekable();

    while let Some(c) = iter.next() {
        match c {
            '\'' => {
                match *build_type {
                    BuildType::Single => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Single;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\"' => {
                match *build_type {
                    BuildType::Double => {
                        *build_type = BuildType::None;
                        if iter.peek() == Some(&' ') {
                            result.push(build_string.clone());
                            *build_string = String::from("");
                        }
                    }

                    BuildType::None => {
                        *build_type = BuildType::Double;
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            ' ' => {
                match *build_type {
                    BuildType::None => {
                        result.push(build_string.clone());
                        *build_string = String::from("");
                    }

                    _ => {
                        build_string.push(c);
                    }
                }
            }

            '\n' => {
                match *build_type {
                    BuildType::None => {
                        match iter.peek() {
                            Some(_) => {
                                build_string.push(c);
                            }
                            None => {}
                        }
                    }
                    _ => {
                        build_string.push(c);
                    }
                }
            }

            _ => {
                build_string.push(c);
            }
        }
    }

    if *build_type == BuildType::None {
        *completed = true;
        if build_string.len() > 0 {
            result.push(build_string.clone());
        }
    }
}

#[test]
fn parse_args_test() {
    // parse empty string
    {
        let expected: Vec<String> = Vec::new();
        let result = parse_args(&String::from(""));
        assert_eq!(result, expected);
    }

    // parse single-word string
    {
        let expected: Vec<String> = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo"));
        assert_eq!(result, expected);
    }

    // parse single-word string inside quotes
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("\"echo\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with closed quotes section
    {
        let expected = vec!["echo".to_string(), "-n".into(), "Hello Dear World".into()];
        let result = parse_args(&String::from("echo -n \"Hello Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with multiple closed quotes sections
    {
        let expected = vec!["echo".to_string(), "Hello".into(), "Dear World".into()];
        let result = parse_args(&String::from("echo \"Hello\" \"Dear World\""));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around single quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo 'hello'world"));
        assert_eq!(result, expected);
    }

    // parse multi-word string with no spaces around double quotes
    {
        let expected = vec!["echo".to_string(), "helloworld".into()];
        let result = parse_args(&String::from("echo \"hello\"world"));
        assert_eq!(result, expected);
    }

    // allow double quotes inside single quotes
    {
        let expected = vec!["\"".to_string()];
        let result = parse_args(&String::from("'\"'"));
        assert_eq!(result, expected);
    }

    // allow single quotes inside double quotes
    {
        let expected = vec!["\'".to_string()];
        let result = parse_args(&String::from("\"\'\""));
        assert_eq!(result, expected);
    }

    // handle multiple quote sections in succession
    {
        let expected = vec!["echo".to_string(), "hello world how are you".into()];
        let result = parse_args(&String::from("echo \"hello world\"\' how are you\'"));
        assert_eq!(result, expected);
    }

    // preserve newlines
    {
        let expected = vec!["echo".to_string(), "hello\nworld".into()];
        let result = parse_args(&String::from("echo \"hello\nworld\""));
        assert_eq!(result, expected);
    }

    // remove final newline
    {
        let expected = vec!["echo".to_string()];
        let result = parse_args(&String::from("echo\n"));
        assert_eq!(result, expected);
    }
}
<|endoftext|>


<commit_before><commit_msg>derive Debug for StringScanner and LastMatch structs<commit_after><|endoftext|>


<commit_before>//! Create textures and build texture atlas.

use gfx;
use gfx::CommandBuffer;
use gfx::Device;
use image;
use image::{ GenericImage, ImageBuf, MutableRefImage, Pixel, Rgba, SubImage };
use std::collections::HashMap;
use std::collections::hashmap::{ Occupied, Vacant };
use std::mem;

/// Loads RGBA image from path.
fn load_rgba8(path: &Path) -> Result<ImageBuf<Rgba<u8>>, String> {
    Ok(match image::open(path) {
        Ok(image::ImageRgba8(img)) => img,
        Ok(image::ImageRgb8(img)) => {
            let (w, h) = img.dimensions();
            ImageBuf::from_fn(w, h, |x, y| img.get_pixel(x, y).to_rgba())
        }
        Ok(img) => {
            return Err(format!("Unsupported color type {} in '{}'",
                img.color(), path.display()));
        }
        Err(e)  => {
            return Err(format!("Could not load '{}': {}", path.display(), e));
        }
    })
}

/// Represents a texture.
pub struct Texture {
    /// The Gfx texture handle.
    pub tex: gfx::TextureHandle,
    /// The width of the texture.
    pub width: u32,
    /// The height of the texture.
    pub height: u32
}

impl Texture {
    /// Loads image by relative file name to the asset root.
    pub fn from_path<D: Device<C>, C: CommandBuffer>(path: &Path, d: &mut D)
                                                     -> Result<Texture, String> {
        Ok(Texture::from_rgba8(try!(load_rgba8(path)), d))
    }

    /// Creates a texture from RGBA image.
    pub fn from_rgba8<D: Device<C>, C: CommandBuffer>(
        img: ImageBuf<Rgba<u8>>,
        d: &mut D
    ) -> Texture {
        let (width, height) = img.dimensions();

        let mut ti = gfx::tex::TextureInfo::new();
        ti.width = width as u16;
        ti.height = height as u16;
        ti.kind = gfx::tex::Texture2D;
        ti.format = gfx::tex::RGBA8;

        let tex = d.create_texture(ti).unwrap();
        d.update_texture(&tex, &ti.to_image_info(),
                         img.into_vec().as_slice()).unwrap();
        d.generate_mipmap(&tex);

        Texture {
            tex: tex,
            width: width,
            height: height
        }
    }
}

/// A 256x256 image that stores colors.
pub struct ColorMap {
    image: ImageBuf<Rgba<u8>>
}

impl ColorMap {
    /// Creates a new `ColorMap` from path.
    pub fn from_path(path: &Path) -> Result<ColorMap, String> {
        let img = try!(load_rgba8(path));

        match img.dimensions() {
            (256, 256) => Ok(ColorMap {image: img}),
            (w, h) => Err(format!("ColorMap expected 256x256, found {}x{} in '{}'",
                                  w, h, path.display()))
        }
    }

    /// Gets RGB color from the color map.
    pub fn get(&self, x: f32, y: f32) -> [u8, ..3] {
        // Clamp to [0.0, 1.0].
        let x = x.max(0.0).min(1.0);
        let y = y.max(0.0).min(1.0);

        // Scale y from [0.0, 1.0] to [0.0, x], forming a triangle.
        let y = x * y;

        // Origin is in the bottom-right corner.
        let x = ((1.0 - x) * 255.0) as u8;
        let y = ((1.0 - y) * 255.0) as u8;

        let (r, g, b, _) = self.image.get_pixel(x as u32, y as u32).channels();
        [r, g, b]
    }
}

/// Builds an atlas of textures.
pub struct AtlasBuilder {
    image: ImageBuf<Rgba<u8>>,
    // Base path for loading tiles.
    path: Path,
    // Size of an individual tile.
    unit_width: u32,
    unit_height: u32,
    // Size of the entirely occupied square, in tiles.
    completed_tiles_size: u32,
    // Position in the current strip.
    position: u32,
    // Position cache for loaded tiles (in pixels).
    tile_positions: HashMap<String, (u32, u32)>,
    // Lowest-alpha cache for rectangles in the atlas.
    min_alpha_cache: HashMap<(u32, u32, u32, u32), u8>
}

impl AtlasBuilder {
    /// Creates a new `AtlasBuilder`.
    pub fn new(path: Path, unit_width: u32, unit_height: u32) -> AtlasBuilder {
        AtlasBuilder {
            image: ImageBuf::new(unit_width * 4, unit_height * 4),
            path: path,
            unit_width: unit_width,
            unit_height: unit_height,
            completed_tiles_size: 0,
            position: 0,
            tile_positions: HashMap::new(),
            min_alpha_cache: HashMap::new()
        }
    }

    /// Loads a file into the texture atlas.
    /// Checks if the file is loaded and returns position within the atlas.
    /// The name should be specified without file extension.
    /// PNG is the only supported format.
    pub fn load(&mut self, name: &str) -> (u32, u32) {
        match self.tile_positions.find_equiv(&name) {
            Some(pos) => return *pos,
            None => {}
        }

        let mut path = self.path.join(name);
        path.set_extension("png");
        let img = load_rgba8(&path).unwrap();

        let (iw, ih) = img.dimensions();
        assert!(iw == self.unit_width);
        assert!((ih % self.unit_height) == 0);
        if ih > self.unit_height {
            println!("ignoring {} extra frames in '{}'", (ih / self.unit_height) - 1, name);
        }

        let (uw, uh) = (self.unit_width, self.unit_height);
        let (w, h) = self.image.dimensions();
        let size = self.completed_tiles_size;

        // Expand the image buffer if necessary.
        if self.position == 0 && (uw * size >= w || uh * size >= h) {
            let old = mem::replace(&mut self.image, ImageBuf::new(w * 2, h * 2));
            let mut dest = SubImage::new(&mut self.image, 0, 0, w, h);
            for ((_, _, a), (_, _, b)) in dest.mut_pixels().zip(old.pixels()) {
                *a = b;
            }
        }

        let (x, y) = if self.position < size {
            (self.position, size)
        } else {
            (size, self.position - size)
        };

        self.position += 1;
        if self.position >= size * 2 + 1 {
            self.position = 0;
            self.completed_tiles_size += 1;
        }

        let mut dest = SubImage::new(&mut self.image, x * uw, y * uh, uw, uh);
        for ((_, _, a), (_, _, b)) in dest.mut_pixels().zip(img.pixels()) {
            *a = b;
        }

        *match self.tile_positions.entry(name.to_string()) {
            Occupied(entry) => entry.into_mut(),
            Vacant(entry) => entry.set((x * uw, y * uh))
        }
    }

    /// Finds the minimum alpha value in a given sub texture of the image.
    pub fn min_alpha(&mut self, x: u32, y: u32, w: u32, h: u32) -> u8 {
        match self.min_alpha_cache.find(&(x, y, w, h)) {
            Some(alpha) => return *alpha,
            None => {}
        }

        let tile = SubImage::new(&mut self.image, x, y, w, h);
        let min_alpha = tile.pixels().map(|(_, _, p)| p.alpha())
            .min().unwrap_or(0);
        self.min_alpha_cache.insert((x, y, w, h), min_alpha);
        min_alpha
    }

    /// Returns the complete texture atlas as a texture.
    pub fn complete<D: Device<C>, C: CommandBuffer>(self, d: &mut D) -> Texture {
        Texture::from_rgba8(self.image, d)
    }
}
<commit_msg>Use `rect: [u32, ..4]` in min_alpha<commit_after>//! Create textures and build texture atlas.

use gfx;
use gfx::CommandBuffer;
use gfx::Device;
use image;
use image::{ GenericImage, ImageBuf, MutableRefImage, Pixel, Rgba, SubImage };
use std::collections::HashMap;
use std::collections::hashmap::{ Occupied, Vacant };
use std::mem;

/// Loads RGBA image from path.
fn load_rgba8(path: &Path) -> Result<ImageBuf<Rgba<u8>>, String> {
    Ok(match image::open(path) {
        Ok(image::ImageRgba8(img)) => img,
        Ok(image::ImageRgb8(img)) => {
            let (w, h) = img.dimensions();
            ImageBuf::from_fn(w, h, |x, y| img.get_pixel(x, y).to_rgba())
        }
        Ok(img) => {
            return Err(format!("Unsupported color type {} in '{}'",
                img.color(), path.display()));
        }
        Err(e)  => {
            return Err(format!("Could not load '{}': {}", path.display(), e));
        }
    })
}

/// Represents a texture.
pub struct Texture {
    /// The Gfx texture handle.
    pub tex: gfx::TextureHandle,
    /// The width of the texture.
    pub width: u32,
    /// The height of the texture.
    pub height: u32
}

impl Texture {
    /// Loads image by relative file name to the asset root.
    pub fn from_path<D: Device<C>, C: CommandBuffer>(path: &Path, d: &mut D)
                                                     -> Result<Texture, String> {
        Ok(Texture::from_rgba8(try!(load_rgba8(path)), d))
    }

    /// Creates a texture from RGBA image.
    pub fn from_rgba8<D: Device<C>, C: CommandBuffer>(
        img: ImageBuf<Rgba<u8>>,
        d: &mut D
    ) -> Texture {
        let (width, height) = img.dimensions();

        let mut ti = gfx::tex::TextureInfo::new();
        ti.width = width as u16;
        ti.height = height as u16;
        ti.kind = gfx::tex::Texture2D;
        ti.format = gfx::tex::RGBA8;

        let tex = d.create_texture(ti).unwrap();
        d.update_texture(&tex, &ti.to_image_info(),
                         img.into_vec().as_slice()).unwrap();
        d.generate_mipmap(&tex);

        Texture {
            tex: tex,
            width: width,
            height: height
        }
    }
}

/// A 256x256 image that stores colors.
pub struct ColorMap {
    image: ImageBuf<Rgba<u8>>
}

impl ColorMap {
    /// Creates a new `ColorMap` from path.
    pub fn from_path(path: &Path) -> Result<ColorMap, String> {
        let img = try!(load_rgba8(path));

        match img.dimensions() {
            (256, 256) => Ok(ColorMap {image: img}),
            (w, h) => Err(format!("ColorMap expected 256x256, found {}x{} in '{}'",
                                  w, h, path.display()))
        }
    }

    /// Gets RGB color from the color map.
    pub fn get(&self, x: f32, y: f32) -> [u8, ..3] {
        // Clamp to [0.0, 1.0].
        let x = x.max(0.0).min(1.0);
        let y = y.max(0.0).min(1.0);

        // Scale y from [0.0, 1.0] to [0.0, x], forming a triangle.
        let y = x * y;

        // Origin is in the bottom-right corner.
        let x = ((1.0 - x) * 255.0) as u8;
        let y = ((1.0 - y) * 255.0) as u8;

        let (r, g, b, _) = self.image.get_pixel(x as u32, y as u32).channels();
        [r, g, b]
    }
}

/// Builds an atlas of textures.
pub struct AtlasBuilder {
    image: ImageBuf<Rgba<u8>>,
    // Base path for loading tiles.
    path: Path,
    // Size of an individual tile.
    unit_width: u32,
    unit_height: u32,
    // Size of the entirely occupied square, in tiles.
    completed_tiles_size: u32,
    // Position in the current strip.
    position: u32,
    // Position cache for loaded tiles (in pixels).
    tile_positions: HashMap<String, (u32, u32)>,
    // Lowest-alpha cache for rectangles in the atlas.
    min_alpha_cache: HashMap<(u32, u32, u32, u32), u8>
}

impl AtlasBuilder {
    /// Creates a new `AtlasBuilder`.
    pub fn new(path: Path, unit_width: u32, unit_height: u32) -> AtlasBuilder {
        AtlasBuilder {
            image: ImageBuf::new(unit_width * 4, unit_height * 4),
            path: path,
            unit_width: unit_width,
            unit_height: unit_height,
            completed_tiles_size: 0,
            position: 0,
            tile_positions: HashMap::new(),
            min_alpha_cache: HashMap::new()
        }
    }

    /// Loads a file into the texture atlas.
    /// Checks if the file is loaded and returns position within the atlas.
    /// The name should be specified without file extension.
    /// PNG is the only supported format.
    pub fn load(&mut self, name: &str) -> (u32, u32) {
        match self.tile_positions.find_equiv(&name) {
            Some(pos) => return *pos,
            None => {}
        }

        let mut path = self.path.join(name);
        path.set_extension("png");
        let img = load_rgba8(&path).unwrap();

        let (iw, ih) = img.dimensions();
        assert!(iw == self.unit_width);
        assert!((ih % self.unit_height) == 0);
        if ih > self.unit_height {
            println!("ignoring {} extra frames in '{}'", (ih / self.unit_height) - 1, name);
        }

        let (uw, uh) = (self.unit_width, self.unit_height);
        let (w, h) = self.image.dimensions();
        let size = self.completed_tiles_size;

        // Expand the image buffer if necessary.
        if self.position == 0 && (uw * size >= w || uh * size >= h) {
            let old = mem::replace(&mut self.image, ImageBuf::new(w * 2, h * 2));
            let mut dest = SubImage::new(&mut self.image, 0, 0, w, h);
            for ((_, _, a), (_, _, b)) in dest.mut_pixels().zip(old.pixels()) {
                *a = b;
            }
        }

        let (x, y) = if self.position < size {
            (self.position, size)
        } else {
            (size, self.position - size)
        };

        self.position += 1;
        if self.position >= size * 2 + 1 {
            self.position = 0;
            self.completed_tiles_size += 1;
        }

        let mut dest = SubImage::new(&mut self.image, x * uw, y * uh, uw, uh);
        for ((_, _, a), (_, _, b)) in dest.mut_pixels().zip(img.pixels()) {
            *a = b;
        }

        *match self.tile_positions.entry(name.to_string()) {
            Occupied(entry) => entry.into_mut(),
            Vacant(entry) => entry.set((x * uw, y * uh))
        }
    }

    /// Finds the minimum alpha value in a given sub texture of the image.
    pub fn min_alpha(&mut self, rect: [u32, ..4]) -> u8 {
        let [x, y, w, h] = rect;
        match self.min_alpha_cache.find(&(x, y, w, h)) {
            Some(alpha) => return *alpha,
            None => {}
        }

        let tile = SubImage::new(&mut self.image, x, y, w, h);
        let min_alpha = tile.pixels().map(|(_, _, p)| p.alpha())
            .min().unwrap_or(0);
        self.min_alpha_cache.insert((x, y, w, h), min_alpha);
        min_alpha
    }

    /// Returns the complete texture atlas as a texture.
    pub fn complete<D: Device<C>, C: CommandBuffer>(self, d: &mut D) -> Texture {
        Texture::from_rgba8(self.image, d)
    }
}
<|endoftext|>


<commit_before>// The code in this file is based on Rust's compiler-builtins crate. The Rust
// compiler automatically links programs against this crate for target-specific
// runtime support. We have copied the implementation of `__udivmodti4()` which
// is an intrinsic implementing division with remainder for architectures
// without 128-bit integers. This implementation works around some poor codegen
// by LLVM (https://github.com/rust-lang/rust/issues/44545) and allows for
// inlining which does not happen with the intrinsic.
//
// The compiler-builtins crate carries the following license, which is available
// in full at:
// https://github.com/rust-lang-nursery/compiler-builtins/blob/master/LICENSE.TXT
//
// ---
//
// Copyright 2009-2016 compiler-builtins Developers
//
// The compiler-builtins crate is dual licensed under both the University of
// Illinois "BSD-Like" license and the MIT license. As a user of this code you
// may choose to use it under either license. As a contributor, you agree to
// allow your code to be used under both.

#[inline]
pub fn udivmod_1e19(n: u128) -> (u128, u64) {
    let d = 10_000_000_000_000_000_000_u64; // 10^19

    let high = (n >> 64) as u64;
    if high == 0 {
        let low = n as u64;
        return ((low / d) as u128, low % d);
    }

    let sr = 65 - high.leading_zeros();

    // 2 <= sr <= 65
    let mut q: u128 = n << (128 - sr);
    let mut r: u128 = n >> sr;
    let mut carry: u64 = 0;

    // Don't use a range because they may generate references to memcpy in unoptimized code
    //
    // Loop invariants:  r < d; carry is 0 or 1
    let mut i = 0;
    while i < sr {
        i += 1;

        // r:q = ((r:q) << 1) | carry
        r = (r << 1) | (q >> 127);
        q = (q << 1) | carry as u128;

        // carry = 0
        // if r >= d {
        //     r -= d;
        //     carry = 1;
        // }
        let s = (d as u128).wrapping_sub(r).wrapping_sub(1) as i128 >> 127;
        carry = (s & 1) as u64;
        r -= (d as u128) & s as u128;
    }

    ((q << 1) | carry as u128, r as u64)
}
<commit_msg>perf: Optimize udivmod_1e19 function<commit_after>/// Multiply unsigned 128 bit integers, return upper 128 bits of the result
#[inline]
fn u128_mulhi(x: u128, y: u128) -> u128 {
    let x_lo = x as u64;
    let x_hi = (x >> 64) as u64;
    let y_lo = y as u64;
    let y_hi = (y >> 64) as u64;

    // handle possibility of overflow
    let carry = (x_lo as u128 * y_lo as u128) >> 64;
    let m = x_lo as u128 * y_hi as u128 + carry;
    let high1 = m >> 64;

    let m_lo = m as u64;
    let high2 = x_hi as u128 * y_lo as u128 + m_lo as u128 >> 64;

    x_hi as u128 * y_hi as u128 + high1 + high2
}

/// Divide `n` by 1e19 and return quotient and remainder
///
/// Integer division algorithm is based on the following paper:
///
///   T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
///   in Proc. of the SIGPLAN94 Conference on Programming Language Design and
///   Implementation, 1994, pp. 61–72
///
#[inline]
pub fn udivmod_1e19(n: u128) -> (u128, u64) {
    let d = 10_000_000_000_000_000_000_u64; // 10^19

    let quot = if n < 1 << 83 {
        ((n >> 19) as u64 / (d >> 19)) as u128
    } else {
        let factor = 156927543384667019095894735580191660403_u128;
        u128_mulhi(n, factor) >> 62
    };

    let rem = (n - quot * d as u128) as u64;
    debug_assert_eq!(quot, n / d as u128);
    debug_assert_eq!(rem as u128, n % d as u128);

    (quot, rem)
}
<|endoftext|>


<commit_before><commit_msg>Take closure in begin_update by move<commit_after><|endoftext|>


<commit_before>#![crate_type = "rlib"]

//! Macro to create a "view box", a box containing immutable data
//! plus a "view" struct that can have interior references into
//! the data.  The view box can be moved around as an atomic unit.
//! I haven't completely convinced myself this is memory safe yet.
//! In particular, I need to make sure dangling pointers can't be
//! observed if the view struct implements Drop
#![feature(macro_rules, globs)]

#[macro_export]
macro_rules! viewbox(
    (struct $name:ident<$d:ty, $v:ident>;) => (
        pub struct $name {
            data: Box<$d>,
            view: $v<'static>
        }

        #[allow(dead_code)]
        impl $name {
            pub fn new(data: $d, f: <'a>|&'a mut $d| -> $v<'a>) -> $name {
                let mut d = box data;
                let v = unsafe { ::std::mem::transmute(f(&mut *d)) };

                $name { data: d, view: v }
            }

            pub fn new_result<E>(data: $d,
                                 f: <'a>|&'a mut $d|
                                    -> ::std::result::Result<$v<'a>,E>)
                                 -> ::std::result::Result<$name,($d,E)> {
                let mut d = box data;
                match f(&mut *d).map(|v| unsafe { ::std::mem::transmute(v) }) {
                    Ok(v) => Ok($name { data: d, view: v }),
                    Err(e) => Err((*d,e))
                }
            }

            pub fn unwrap(self)-> $d {
                let $name { data: box data, .. } = self;
                data
            }

            pub fn view<'a>(&'a self) -> &'a $v<'a> {
                unsafe { ::std::mem::transmute(&self.view) }
            }

            pub fn mut_view<'a>(&'a mut self) -> &'a mut $v<'a> {
                unsafe { ::std::mem::transmute(&mut self.view) }
            }
        }
    );
    (#[deriving(PartialEq $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &$name) -> bool { self.view() == other.view(); }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving(Show $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::fmt::Show for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
                   -> ::std::result::Result<(), ::std::fmt::FormatError> {
                self.view().fmt(fmt)
            }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving()] struct $name:ident<$d:ty, $v:ident>;) => (
        viewbox!(struct $name<$d,$v>;)
    );
)

#[cfg(test)]
mod test {
    // Test data structure
    #[deriving(PartialEq,Show)]
    struct TestData {
        foo: i32,
        bar: String
    }

    // View structure that has references into the boxed data
    struct TestView<'a> {
        x: &'a i32,
        y: &'a str
    }

    // Create TestBox which combines TestData and TestView
    viewbox! {
        struct TestBox<TestData,TestView>;
    }

    // Mutable view into string
    struct MutView<'a> {
        x: &'a mut String
    }

    // MutBox combines TestData and MutView
    viewbox! {
        struct MutBox<TestData, MutView>;
    }

    #[test]
    fn basic() {
        // Create some data
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        // Move it into box, creating a view with interior references
        let v = TestBox::new(t, |d| TestView { x: &d.foo, y: d.bar.as_slice() });

        // We can access the boxed data via the view
        assert_eq!(v.view().x, &42i32);
        assert_eq!(v.view().y, "Hello");
        // We can unwrap the view to get the data back
        let t = v.unwrap();
        assert_eq!(t.foo, 42i32);
        assert_eq!(t.bar, "Hello".to_string());
    }

    #[test]
    fn mutation() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let mut v = MutBox::new(t, |d| MutView { x: &mut d.bar });

        *v.mut_view().x = "Goodbye".to_string();
        let t = v.unwrap();
        assert_eq!(t.bar, "Goodbye".to_string());
    }

    #[test]
    fn error() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let v = MutBox::new_result(t, |_| Err("Nope")).err().unwrap();
        assert_eq!(v, (TestData { foo: 42, bar: "Hello".to_string() }, "Nope"))
    }
}
<commit_msg>Start making notes of memory safety issues to address<commit_after>#![crate_type = "rlib"]

//! Macro to create a "view box", a box containing immutable data plus
//! a "view" struct that can have interior references into the data.
//! The view box can be moved around as an atomic unit.  I haven't
//! convinced myself this is memory safe yet.  Known issues:
//!
//! * If the view type implements Drop (via #[unsafe_destructor]), it
//! could potentially observe dangling references depending on the
//! order in which struct fields are destroyed.
#![feature(macro_rules, globs)]

#[macro_export]
macro_rules! viewbox(
    (struct $name:ident<$d:ty, $v:ident>;) => (
        pub struct $name {
            data: Box<$d>,
            view: $v<'static>
        }

        #[allow(dead_code)]
        impl $name {
            pub fn new(data: $d, f: <'a>|&'a mut $d| -> $v<'a>) -> $name {
                let mut d = box data;
                let v = unsafe { ::std::mem::transmute(f(&mut *d)) };

                $name { data: d, view: v }
            }

            pub fn new_result<E>(data: $d,
                                 f: <'a>|&'a mut $d|
                                    -> ::std::result::Result<$v<'a>,E>)
                                 -> ::std::result::Result<$name,($d,E)> {
                let mut d = box data;
                match f(&mut *d).map(|v| unsafe { ::std::mem::transmute(v) }) {
                    Ok(v) => Ok($name { data: d, view: v }),
                    Err(e) => Err((*d,e))
                }
            }

            pub fn unwrap(self)-> $d {
                let $name { data: box data, .. } = self;
                data
            }

            pub fn view<'a>(&'a self) -> &'a $v<'a> {
                unsafe { ::std::mem::transmute(&self.view) }
            }

            pub fn mut_view<'a>(&'a mut self) -> &'a mut $v<'a> {
                unsafe { ::std::mem::transmute(&mut self.view) }
            }
        }
    );
    (#[deriving(PartialEq $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::cmp::PartialEq for $name {
            fn eq(&self, other: &$name) -> bool { self.view() == other.view(); }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving(Show $(,$derive:ident)*)] struct $name:ident<$d:ty, $v:ident>;) => (
        impl ::std::fmt::Show for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
                   -> ::std::result::Result<(), ::std::fmt::FormatError> {
                self.view().fmt(fmt)
            }
        }
        viewbox!(struct $name<$d,$v>;)
    );
    (#[deriving()] struct $name:ident<$d:ty, $v:ident>;) => (
        viewbox!(struct $name<$d,$v>;)
    );
)

#[cfg(test)]
mod test {
    // Test data structure
    #[deriving(PartialEq,Show)]
    struct TestData {
        foo: i32,
        bar: String
    }

    // View structure that has references into the boxed data
    struct TestView<'a> {
        x: &'a i32,
        y: &'a str
    }

    // Create TestBox which combines TestData and TestView
    viewbox! {
        struct TestBox<TestData,TestView>;
    }

    // Mutable view into string
    struct MutView<'a> {
        x: &'a mut String
    }

    // MutBox combines TestData and MutView
    viewbox! {
        struct MutBox<TestData, MutView>;
    }

    #[test]
    fn basic() {
        // Create some data
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        // Move it into box, creating a view with interior references
        let v = TestBox::new(t, |d| TestView { x: &d.foo, y: d.bar.as_slice() });

        // We can access the boxed data via the view
        assert_eq!(v.view().x, &42i32);
        assert_eq!(v.view().y, "Hello");
        // We can unwrap the view to get the data back
        let t = v.unwrap();
        assert_eq!(t.foo, 42i32);
        assert_eq!(t.bar, "Hello".to_string());
    }

    #[test]
    fn mutation() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let mut v = MutBox::new(t, |d| MutView { x: &mut d.bar });

        *v.mut_view().x = "Goodbye".to_string();
        let t = v.unwrap();
        assert_eq!(t.bar, "Goodbye".to_string());
    }

    #[test]
    fn error() {
        let t = TestData { foo: 42, bar: "Hello".to_string() };
        let v = MutBox::new_result(t, |_| Err("Nope")).err().unwrap();
        assert_eq!(v, (TestData { foo: 42, bar: "Hello".to_string() }, "Nope"))
    }
}
<|endoftext|>


<commit_before>// 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.

extern crate commands;
extern crate rustyline;

use commands::parser::{Command, CommandTree, ParseError, Parser};
use commands::tokenizer::tokenize;

fn main() {
    let mut tree = CommandTree::new();
    tree.command(Command::new("show"));
    let root = tree.finalize();

    let mut rl = rustyline::Editor::<()>::new();
    while let Ok(line) = rl.readline(">> ") {
        rl.add_history_entry(&line);
        if let Ok(tokens) = tokenize(&line) {
            let mut parser = Parser::new(root.clone());
            if let Err(err) = parser.parse(tokens) {
                match err {
                    ParseError::NoMatches(_, acceptable) => {
                        println!("No match for '{}'", line);
                        println!("\nPossible options:");
                        for ref option in acceptable {
                            let n = option.node();
                            println!("  {} - {}", n.help_symbol, n.help_text);
                        }
                    }
                    ParseError::AmbiguousMatch(_, matches) => {
                        println!("\nCan be interpreted as:");
                        for ref option in matches {
                            let n = option.node();
                            println!("  {} - {}", n.help_symbol, n.help_text);
                        }
                    }
                }
            } else if let Err(err) = parser.verify() {
                println!("{}", err);
            } else {
                parser.execute();
            }
        }
        println!("");
    }
    println!("\nExiting.");
}
<commit_msg>Start work on Rustyline completion support.<commit_after>// 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.

extern crate commands;
extern crate rustyline;

use commands::parser::{Command, CommandTree, Node, ParseError, Parser};
use commands::tokenizer::tokenize;
use rustyline::{Editor, Result};
use rustyline::completion::Completer;
use std::rc::Rc;

struct CommandCompleter {
    root: Rc<Node>,
}

impl CommandCompleter {
    fn new(root: Rc<Node>) -> Self {
        CommandCompleter { root: root }
    }
}

impl Completer for CommandCompleter {
    fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
        // TODO: This is an initial implementation that needs a lot more work.
        if let Ok(tokens) = tokenize(line) {
            let p = Parser::new(self.root.clone());
            let cs = p.complete(Some(tokens[0]));
            if !cs.is_empty() {
                Ok((0,
                    cs[0]
                        .options
                        .iter()
                        .map(|co| co.option_string.clone())
                        .collect()))
            } else {
                Ok((0, Vec::new()))
            }
        } else {
            Ok((0, Vec::new()))
        }
    }
}

fn main() {
    let mut tree = CommandTree::new();
    tree.command(Command::new("show"));
    let root = tree.finalize();

    let c = CommandCompleter::new(root.clone());
    let mut rl = Editor::<CommandCompleter>::new();
    rl.set_completer(Some(c));
    while let Ok(line) = rl.readline(">> ") {
        rl.add_history_entry(&line);
        if let Ok(tokens) = tokenize(&line) {
            let mut parser = Parser::new(root.clone());
            if let Err(err) = parser.parse(tokens) {
                match err {
                    ParseError::NoMatches(_, acceptable) => {
                        println!("No match for '{}'", line);
                        println!("\nPossible options:");
                        for ref option in acceptable {
                            let n = option.node();
                            println!("  {} - {}", n.help_symbol, n.help_text);
                        }
                    }
                    ParseError::AmbiguousMatch(_, matches) => {
                        println!("\nCan be interpreted as:");
                        for ref option in matches {
                            let n = option.node();
                            println!("  {} - {}", n.help_symbol, n.help_text);
                        }
                    }
                }
            } else if let Err(err) = parser.verify() {
                println!("{}", err);
            } else {
                parser.execute();
            }
        }
        println!("");
    }
    println!("\nExiting.");
}
<|endoftext|>


<commit_before>generate_error_module!(
    generate_error_types!(HookError, HookErrorKind,
        HookExecutionError  => "Hook exec error",
        AccessTypeViolation => "Hook access type violation"
    );
);

pub use self::error::HookError;
pub use self::error::HookErrorKind;

<commit_msg>HookError: Add optional non-aborting mode<commit_after>use std::convert::Into;
generate_error_imports!();

generate_custom_error_types!(HookError, HookErrorKind, CustomData,
    HookExecutionError  => "Hook exec error",
    AccessTypeViolation => "Hook access type violation"
);

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
pub struct CustomData {
    aborting: bool,
}

impl HookError {

    pub fn is_aborting(&self) -> bool {
        match self.custom_data {
            Some(b) => b.aborting,
            None => true
        }
    }

}
<|endoftext|>


<commit_before>use std::time::Duration;

pub fn short_timeout() -> Duration {
    Duration::from_secs(10)
}

pub fn medium_timeout() -> Duration {
    Duration::from_secs(300)
}

pub fn long_timeout() -> Duration {
    Duration::from_secs(500)
}
<commit_msg>Extend long timeout for Android CI anoncreds tests.<commit_after>use std::time::Duration;

pub fn short_timeout() -> Duration {
    Duration::from_secs(10)
}

pub fn medium_timeout() -> Duration {
    Duration::from_secs(300)
}

pub fn long_timeout() -> Duration {
    Duration::from_secs(1000)
}
<|endoftext|>