<commit_before>#![feature(core)]
#![feature(process)]
#![feature(fs)]
#![feature(path)]
#![feature(env)]

extern crate docopt;

#[macro_use]
extern crate standard_error;

use docopt::Docopt;
use standard_error::StandardResult as Result;
use std::rc::Rc;
use std::fs::PathExt;

mod git;
mod author;
mod pair;
mod config;
mod concat;

use author::Author;
use pair::Pair;
use config::Config;
use std::borrow::Cow;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: partners current
       partners list
       partners add --nick=<nick> --name=<name> [--email=<email>]
       partners add
       partners set <nick>...
       partners (--help | --version)

Options:
    -h, --help      Show help
    --version       Show version information
";

trait AuthorInformation {
    fn get_nick(&self) -> Cow<str>;
    fn get_name(&self) -> Cow<str>;
    fn get_email(&self) -> Cow<str>;
}

fn print_author_list(list: &[Author]) {
    for item in list.iter() {
        println!("{}:", item.nick);
        println!("  Name:  {}", item.name);
        println!("  Email: {}", item.get_email());
    }
}

fn parse_author_line(config: Rc<Config>, line: &str) -> Result<Author> {
    let mut parts = line.splitn(1, ' ');
    let nick = parts.next().unwrap().split('.').nth(1).unwrap().to_string();
    let name = parts.next().unwrap().to_string();
    let email = config.git.get(&format!("author.{}.email", nick)).ok();

    Ok(Author { config: config, nick: nick, name: name, email: email })
}

fn get_authors(config: Rc<Config>) -> Result<Vec<Author>> {
    let lines = try!(config.git.list("author.\\w+.name"));
    lines.iter().map(|line| parse_author_line(config.clone(), line)).collect()
}

fn write_author(author: &Author) -> Result<()> {
    try!(author.config.git.set(&format!("author.{}.name", author.nick), &author.name));
    if let Some(ref email) = author.email {
        try!(author.config.git.set(&format!("author.{}.email", author.nick), email));
    }
    Ok(())
}

fn print_current() {
    if let Ok(nick) = git::Config::None.get("partners.current") {
        println!("Nick:  {}", nick);
    }
    if let Ok(name) = git::Config::None.get("user.name") {
        println!("Name:  {}", name);
    }
    if let Ok(email) = git::Config::None.get("user.email") {
        println!("Email: {}", email);
    }
}

fn filter_authors<'a>(authors: &'a [Author], nicks: &[&str]) -> std::result::Result<Vec<&'a Author>, String> {
    nicks.iter().map(|n| authors.iter().find(|a| &a.nick == n).ok_or_else(|| n.to_string())).collect()
}

fn set_current<T>(current: T) -> Result<()> where T: AuthorInformation {
    try!(git::Config::Global.set("partners.current", &current.get_nick()));
    try!(git::Config::Global.set("user.name", &current.get_name()));
    try!(git::Config::Global.set("user.email", &current.get_email()));
    Ok(())
}

fn main() {
    let config_path = std::env::home_dir().expect("can't determine home directory").join(".partners.cfg");

    let docopt = Docopt::new(USAGE).unwrap().help(true).version(Some(env!("CARGO_PKG_VERSION").to_string()));
    let args = docopt.parse().unwrap_or_else(|e| e.exit());

    let config = Rc::new(Config::from_git(git::Config::File(config_path.clone())));

    if !config_path.exists() {
        println!("Config file {:?} does not exist, please run `partners setup`", config_path)
    } else if args.get_bool("list") {
        let authors = get_authors(config).unwrap();
        print_author_list(&authors);
    } else if args.get_bool("add") {
        let email = args.get_str("--email");
        let nick = args.get_str("--nick");
        let name = args.get_str("--name");

        let email = if email.is_empty() { None } else { Some(email.to_string()) };

        let author = Author { config: config.clone(), nick: nick.to_string(), name: name.to_string(), email: email };
        write_author(&author).unwrap();
    } else if args.get_bool("current") {
        print_current();
    } else if args.get_bool("set") {
        let nicks = args.get_vec("<nick>");
        let authors = get_authors(config.clone()).unwrap();
        match filter_authors(&authors, &nicks) {
            Ok(filtered_authors) => {
                println!("{:?}", filtered_authors);
                match filtered_authors.len() {
                    0 => println!("no author specified"),
                    1 => set_current(filtered_authors[0]).unwrap(),
                    _ => {
                        let pair = Pair { config: config.clone(), authors: filtered_authors.as_slice() };
                        set_current(&pair).unwrap()
                    }
                }
                print_current();
            },
            Err(nick) => {
                println!("couldn't find author '{}'", nick);
            }
        }
    }
}
<commit_msg>remove useless debug<commit_after>#![feature(core)]
#![feature(process)]
#![feature(fs)]
#![feature(path)]
#![feature(env)]

extern crate docopt;

#[macro_use]
extern crate standard_error;

use docopt::Docopt;
use standard_error::StandardResult as Result;
use std::rc::Rc;
use std::fs::PathExt;

mod git;
mod author;
mod pair;
mod config;
mod concat;

use author::Author;
use pair::Pair;
use config::Config;
use std::borrow::Cow;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: partners current
       partners list
       partners add --nick=<nick> --name=<name> [--email=<email>]
       partners add
       partners set <nick>...
       partners (--help | --version)

Options:
    -h, --help      Show help
    --version       Show version information
";

trait AuthorInformation {
    fn get_nick(&self) -> Cow<str>;
    fn get_name(&self) -> Cow<str>;
    fn get_email(&self) -> Cow<str>;
}

fn print_author_list(list: &[Author]) {
    for item in list.iter() {
        println!("{}:", item.nick);
        println!("  Name:  {}", item.name);
        println!("  Email: {}", item.get_email());
    }
}

fn parse_author_line(config: Rc<Config>, line: &str) -> Result<Author> {
    let mut parts = line.splitn(1, ' ');
    let nick = parts.next().unwrap().split('.').nth(1).unwrap().to_string();
    let name = parts.next().unwrap().to_string();
    let email = config.git.get(&format!("author.{}.email", nick)).ok();

    Ok(Author { config: config, nick: nick, name: name, email: email })
}

fn get_authors(config: Rc<Config>) -> Result<Vec<Author>> {
    let lines = try!(config.git.list("author.\\w+.name"));
    lines.iter().map(|line| parse_author_line(config.clone(), line)).collect()
}

fn write_author(author: &Author) -> Result<()> {
    try!(author.config.git.set(&format!("author.{}.name", author.nick), &author.name));
    if let Some(ref email) = author.email {
        try!(author.config.git.set(&format!("author.{}.email", author.nick), email));
    }
    Ok(())
}

fn print_current() {
    if let Ok(nick) = git::Config::None.get("partners.current") {
        println!("Nick:  {}", nick);
    }
    if let Ok(name) = git::Config::None.get("user.name") {
        println!("Name:  {}", name);
    }
    if let Ok(email) = git::Config::None.get("user.email") {
        println!("Email: {}", email);
    }
}

fn filter_authors<'a>(authors: &'a [Author], nicks: &[&str]) -> std::result::Result<Vec<&'a Author>, String> {
    nicks.iter().map(|n| authors.iter().find(|a| &a.nick == n).ok_or_else(|| n.to_string())).collect()
}

fn set_current<T>(current: T) -> Result<()> where T: AuthorInformation {
    try!(git::Config::Global.set("partners.current", &current.get_nick()));
    try!(git::Config::Global.set("user.name", &current.get_name()));
    try!(git::Config::Global.set("user.email", &current.get_email()));
    Ok(())
}

fn main() {
    let config_path = std::env::home_dir().expect("can't determine home directory").join(".partners.cfg");

    let docopt = Docopt::new(USAGE).unwrap().help(true).version(Some(env!("CARGO_PKG_VERSION").to_string()));
    let args = docopt.parse().unwrap_or_else(|e| e.exit());

    let config = Rc::new(Config::from_git(git::Config::File(config_path.clone())));

    if !config_path.exists() {
        println!("Config file {:?} does not exist, please run `partners setup`", config_path)
    } else if args.get_bool("list") {
        let authors = get_authors(config).unwrap();
        print_author_list(&authors);
    } else if args.get_bool("add") {
        let email = args.get_str("--email");
        let nick = args.get_str("--nick");
        let name = args.get_str("--name");

        let email = if email.is_empty() { None } else { Some(email.to_string()) };

        let author = Author { config: config.clone(), nick: nick.to_string(), name: name.to_string(), email: email };
        write_author(&author).unwrap();
    } else if args.get_bool("current") {
        print_current();
    } else if args.get_bool("set") {
        let nicks = args.get_vec("<nick>");
        let authors = get_authors(config.clone()).unwrap();
        match filter_authors(&authors, &nicks) {
            Ok(filtered_authors) => {
                match filtered_authors.len() {
                    0 => println!("no author specified"),
                    1 => set_current(filtered_authors[0]).unwrap(),
                    _ => {
                        let pair = Pair { config: config.clone(), authors: filtered_authors.as_slice() };
                        set_current(&pair).unwrap()
                    }
                }
                print_current();
            },
            Err(nick) => {
                println!("couldn't find author '{}'", nick);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate git2;

use git2::{Repository, Remote, Error, Index, Commit};
use git2::build::CheckoutBuilder;
use clap::{Arg, App};
use std::path::Path;
use std::collections::{HashMap, HashSet};

const E_NO_GIT_REPO: i32 = 1;

fn main() {
    let exit_code = real_main();
    std::process::exit(exit_code);
}

fn real_main() -> i32 {
    let options = App::new("git-submerge")
                          .version("0.1")
                          .author("Alexander Batischev <eual.jp@gmail.com>")
                          // TODO: get this in synch with Cargo.toml and README
                          .about("Merges git submodule into the repo as if it was that way \
                                  from the start")
                          .arg(Arg::with_name("SUBMODULE_DIR")
                               .help("The submodule to merge")
                               .required(true)
                               .index(1))
                          .get_matches();
    // We can safely use unwrap() here because if the option is empty, Clap would've already shown
    // the error message and aborted.
    let submodule_dir = options.value_of("SUBMODULE_DIR").unwrap();
    println!("Merging {}...", submodule_dir);

    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => {
            eprintln!("Couldn't find Git repo in the current directory: {}",
                      e.message());
            return E_NO_GIT_REPO;
        }
    };

    // 1. Add submodule as a remote
    let mut remote = add_remote(&repo, submodule_dir).expect("Couldn't add a remote");
    // 2. Fetch submodule's history
    remote.fetch(&[], None, None).expect("Couldn't fetch submodule's history");
    // 3. Find out submodule's HEAD commit id
    let submodule = repo.find_submodule(&submodule_dir)
        .expect("Couldn't find the submodule with expected path");
    let submodule_head = submodule.head_id()
        .expect("Couldn't obtain submodule's HEAD");
    // 4. Rewrite submodule branch's history, moving everything under a single directory named
    //    after the submodule
    let mut submodule_revwalk = get_submodule_revwalk(&repo, &submodule_head);

    let mut old_id_to_new = HashMap::new();

    rewrite_submodule_history(&repo,
                              &mut submodule_revwalk,
                              &mut old_id_to_new,
                              &submodule_dir);
    // 7. Remove submodule's remote
    repo.remote_delete(submodule_dir).expect("Couldn't remove submodule's remote");
    // 8. Run through master's history, doing two things:
    let mut repo_revwalk = get_repo_revwalk(&repo);

    rewrite_repo_history(&repo, &mut repo_revwalk, &mut old_id_to_new, &submodule_dir);

    // It's safe to do force-reset because we checked at the beginning and the repo was clean
    let mut checkoutbuilder = CheckoutBuilder::new();
    checkoutbuilder.force();

    let head = repo.head().expect("Couldn't obtain repo's HEAD");
    let head_id = head.target().expect("Couldn't resolve repo's HEAD to a commit ID");
    let updated_id = old_id_to_new[&head_id];
    let object = repo.find_object(updated_id, None)
        .expect("Couldn't look up an object at which HEAD points");
    repo.reset(&object, git2::ResetType::Hard, Some(&mut checkoutbuilder))
        .expect("Couldn't run force-reset");

    0 // An exit code indicating success
}

fn add_remote<'a>(repo: &'a Repository, submodule_name: &str) -> Result<Remote<'a>, Error> {
    // TODO: randomize remote's name or at least check that it doesn't exist already
    // Maybe use remote_anonymous()
    let url = String::from("./") + submodule_name;
    repo.remote(submodule_name, &url)
}

fn get_submodule_revwalk<'repo>(repo: &'repo git2::Repository,
                                submodule_head: &git2::Oid)
                                -> git2::Revwalk<'repo> {
    let mut revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    // "Topological" and reverse means "parents are always visited before their children".
    // We need that in order to be sure that our old-to-new-ids map always contains everything we
    // need it to contain.
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(*submodule_head).expect("Couldn't add submodule's HEAD to RevWalk list");

    revwalk
}

fn rewrite_submodule_history(repo: &git2::Repository,
                             revwalk: &mut git2::Revwalk,
                             old_id_to_new: &mut HashMap<git2::Oid, git2::Oid>,
                             submodule_dir: &str) {
    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 4.1. Extract the tree
                let commit = repo.find_commit(oid)
                    .expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree()
                    .expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));
                let mut old_index = Index::new()
                    .expect("Couldn't create an in-memory index for commit");
                let mut new_index = Index::new().expect("Couldn't create an in-memory index");
                old_index.read_tree(&tree)
                    .expect(&format!("Couldn't read the commit {} into index", oid));
                // 4.2. Obtain the new tree, where everything from the old one is moved under
                //   a directory named after the submodule
                for entry in old_index.iter() {
                    let mut new_entry = entry;

                    // TODO: what mode, owner, mtime etc. does the newly created dir get?
                    let mut new_path = String::from(submodule_dir);
                    new_path += "/";
                    new_path += &String::from_utf8(new_entry.path)
                        .expect("Failed to convert a path to str");

                    new_entry.path = new_path.into_bytes();
                    new_index.add(&new_entry).expect("Couldn't add an entry to the index");
                }
                let tree_id = new_index.write_tree_to(&repo)
                    .expect("Couldn't write the index into a tree");
                old_id_to_new.insert(tree.id(), tree_id);
                let tree = repo.find_tree(tree_id)
                    .expect("Couldn't retrieve the tree we just created");
                // 4.3. Create new commit with the new tree
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let new_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(new_parent_id)
                            .expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    }
                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0..parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(None,
                            &commit.author(),
                            &commit.committer(),
                            &commit.message().expect("Couldn't retrieve commit's message"),
                            &tree,
                            &parents_refs[..])
                    .expect("Failed to commit");
                // 4.4. Update the map with the new commit's ID
                old_id_to_new.insert(oid, new_commit_id);
            }
            Err(e) => eprintln!("Error walking the submodule's history: {:?}", e),
        }
    }
}

fn get_repo_revwalk<'repo>(repo: &'repo git2::Repository) -> git2::Revwalk<'repo> {
    let mut revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    let head = repo.head().expect("Couldn't obtain repo's HEAD");
    let head_id = head.target().expect("Couldn't resolve repo's HEAD to a commit ID");
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(head_id).expect("Couldn't add repo's HEAD to RevWalk list");

    revwalk
}

fn rewrite_repo_history(repo: &git2::Repository,
                        revwalk: &mut git2::Revwalk,
                        old_id_to_new: &mut HashMap<git2::Oid, git2::Oid>,
                        submodule_dir: &str) {
    let submodule_path = Path::new(submodule_dir);

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 8.1 updating the tree to contain the relevant tree from submodule
                let commit = repo.find_commit(oid)
                    .expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree()
                    .expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));

                let submodule_subdir = match tree.get_path(submodule_path) {
                    Ok(tree) => tree,
                    Err(e) => {
                        if e.code() == git2::ErrorCode::NotFound &&
                           e.class() == git2::ErrorClass::Tree {
                            // It's okay. The tree lacks the subtree corresponding to the
                            // submodule. In other words, the commit doesn't include the submodule.
                            // That's totally fine. Let's map it into itself and move on.
                            old_id_to_new.insert(oid, oid);
                            continue;
                        } else {
                            // Unexpected error; let's report it and abort the program
                            // TODO: clean things up before aborting
                            panic!("Error getting submodule's subdir from the tree: {:?}", e);
                        };
                    }
                };

                // **INVARIANT**: if we got this far, current commit contains a submodule and
                // should be rewritten

                let submodule_commit_id = submodule_subdir.id();
                let new_submodule_commit_id = old_id_to_new[&submodule_commit_id];
                let submodule_commit = repo.find_commit(new_submodule_commit_id)
                    .expect("Couldn't obtain submodule's commit");
                let subtree_id = submodule_commit.tree()
                    .and_then(|t| t.get_path(submodule_path))
                    .and_then(|te| Ok(te.id()))
                    .expect("Couldn't obtain submodule's subtree ID");

                let mut treebuilder = repo.treebuilder(Some(&tree))
                    .expect("Couldn't create TreeBuilder");
                treebuilder.remove(submodule_path)
                    .expect("Couldn't remove submodule path from TreeBuilder");
                treebuilder.insert(submodule_path, subtree_id, 0o040000)
                    .expect("Couldn't add submodule as a subdir to TreeBuilder");
                let new_tree_id = treebuilder.write()
                    .expect("Couldn't write TreeBuilder into a Tree");
                let new_tree = repo.find_tree(new_tree_id)
                    .expect("Couldn't read back the Tree we just wrote");

                // 8.2 in commits that used to update the submodule, add a parent pointing to
                //   appropriate commit in new submodule history
                let mut parent_subtree_ids = HashSet::new();
                for parent in commit.parents() {
                    let parent_tree = parent.tree().expect("Couldn't obtain parent's tree");
                    let parent_subdir_tree_id = parent_tree.get_path(submodule_path)
                        .and_then(|x| Ok(x.id()));

                    match parent_subdir_tree_id {
                        Ok(id) => {
                            parent_subtree_ids.insert(id);
                            ()
                        }
                        Err(e) => {
                            if e.code() == git2::ErrorCode::NotFound &&
                               e.class() == git2::ErrorClass::Tree {
                                // It's okay; carry on.
                                continue;
                            } else {
                                panic!("Error getting submodule's subdir from the tree: {:?}", e);
                            };
                        }
                    }
                }
                // true if
                //
                // o--o--o--A--
                //             `,-C
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--o--A--B
                //
                // false if
                //
                // o--o--o--A--
                //             `,-A
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--A--
                //             `,-B
                //  o--o--o--B-
                let submodule_updated: bool = !parent_subtree_ids.contains(&submodule_commit_id);

                // rewrite the parents if the submodule was updated
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let actual_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(actual_parent_id)
                            .expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    }

                    if submodule_updated {
                        p.push(submodule_commit);
                    }

                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0..parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(None,
                            &commit.author(),
                            &commit.committer(),
                            &commit.message().expect("Couldn't retrieve commit's message"),
                            &new_tree,
                            &parents_refs[..])
                    .expect("Failed to commit");

                old_id_to_new.insert(oid, new_commit_id);
            }
            Err(e) => eprintln!("Error walking the submodule's history: {:?}", e),
        }
    }
}
<commit_msg>Factor out final checkout<commit_after>extern crate clap;
extern crate git2;

use git2::{Repository, Remote, Error, Index, Commit};
use git2::build::CheckoutBuilder;
use clap::{Arg, App};
use std::path::Path;
use std::collections::{HashMap, HashSet};

const E_NO_GIT_REPO: i32 = 1;

fn main() {
    let exit_code = real_main();
    std::process::exit(exit_code);
}

fn real_main() -> i32 {
    let options = App::new("git-submerge")
                          .version("0.1")
                          .author("Alexander Batischev <eual.jp@gmail.com>")
                          // TODO: get this in synch with Cargo.toml and README
                          .about("Merges git submodule into the repo as if it was that way \
                                  from the start")
                          .arg(Arg::with_name("SUBMODULE_DIR")
                               .help("The submodule to merge")
                               .required(true)
                               .index(1))
                          .get_matches();
    // We can safely use unwrap() here because if the option is empty, Clap would've already shown
    // the error message and aborted.
    let submodule_dir = options.value_of("SUBMODULE_DIR").unwrap();
    println!("Merging {}...", submodule_dir);

    let repo = match Repository::open(".") {
        Ok(repo) => repo,
        Err(e) => {
            eprintln!("Couldn't find Git repo in the current directory: {}",
                      e.message());
            return E_NO_GIT_REPO;
        }
    };

    // 1. Add submodule as a remote
    let mut remote = add_remote(&repo, submodule_dir).expect("Couldn't add a remote");
    // 2. Fetch submodule's history
    remote.fetch(&[], None, None).expect("Couldn't fetch submodule's history");
    // 3. Find out submodule's HEAD commit id
    let submodule = repo.find_submodule(&submodule_dir)
        .expect("Couldn't find the submodule with expected path");
    let submodule_head = submodule.head_id()
        .expect("Couldn't obtain submodule's HEAD");
    // 4. Rewrite submodule branch's history, moving everything under a single directory named
    //    after the submodule
    let mut submodule_revwalk = get_submodule_revwalk(&repo, &submodule_head);

    let mut old_id_to_new = HashMap::new();

    rewrite_submodule_history(&repo,
                              &mut submodule_revwalk,
                              &mut old_id_to_new,
                              &submodule_dir);
    // 7. Remove submodule's remote
    repo.remote_delete(submodule_dir).expect("Couldn't remove submodule's remote");
    // 8. Run through master's history, doing two things:
    let mut repo_revwalk = get_repo_revwalk(&repo);

    rewrite_repo_history(&repo, &mut repo_revwalk, &mut old_id_to_new, &submodule_dir);

    // It's safe to do force-reset because we checked at the beginning and the repo was clean
    checkout_rewritten_history(&repo, &old_id_to_new);

    0 // An exit code indicating success
}

fn add_remote<'a>(repo: &'a Repository, submodule_name: &str) -> Result<Remote<'a>, Error> {
    // TODO: randomize remote's name or at least check that it doesn't exist already
    // Maybe use remote_anonymous()
    let url = String::from("./") + submodule_name;
    repo.remote(submodule_name, &url)
}

fn get_submodule_revwalk<'repo>(repo: &'repo git2::Repository,
                                submodule_head: &git2::Oid)
                                -> git2::Revwalk<'repo> {
    let mut revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    // "Topological" and reverse means "parents are always visited before their children".
    // We need that in order to be sure that our old-to-new-ids map always contains everything we
    // need it to contain.
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(*submodule_head).expect("Couldn't add submodule's HEAD to RevWalk list");

    revwalk
}

fn rewrite_submodule_history(repo: &git2::Repository,
                             revwalk: &mut git2::Revwalk,
                             old_id_to_new: &mut HashMap<git2::Oid, git2::Oid>,
                             submodule_dir: &str) {
    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 4.1. Extract the tree
                let commit = repo.find_commit(oid)
                    .expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree()
                    .expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));
                let mut old_index = Index::new()
                    .expect("Couldn't create an in-memory index for commit");
                let mut new_index = Index::new().expect("Couldn't create an in-memory index");
                old_index.read_tree(&tree)
                    .expect(&format!("Couldn't read the commit {} into index", oid));
                // 4.2. Obtain the new tree, where everything from the old one is moved under
                //   a directory named after the submodule
                for entry in old_index.iter() {
                    let mut new_entry = entry;

                    // TODO: what mode, owner, mtime etc. does the newly created dir get?
                    let mut new_path = String::from(submodule_dir);
                    new_path += "/";
                    new_path += &String::from_utf8(new_entry.path)
                        .expect("Failed to convert a path to str");

                    new_entry.path = new_path.into_bytes();
                    new_index.add(&new_entry).expect("Couldn't add an entry to the index");
                }
                let tree_id = new_index.write_tree_to(&repo)
                    .expect("Couldn't write the index into a tree");
                old_id_to_new.insert(tree.id(), tree_id);
                let tree = repo.find_tree(tree_id)
                    .expect("Couldn't retrieve the tree we just created");
                // 4.3. Create new commit with the new tree
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let new_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(new_parent_id)
                            .expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    }
                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0..parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(None,
                            &commit.author(),
                            &commit.committer(),
                            &commit.message().expect("Couldn't retrieve commit's message"),
                            &tree,
                            &parents_refs[..])
                    .expect("Failed to commit");
                // 4.4. Update the map with the new commit's ID
                old_id_to_new.insert(oid, new_commit_id);
            }
            Err(e) => eprintln!("Error walking the submodule's history: {:?}", e),
        }
    }
}

fn get_repo_revwalk<'repo>(repo: &'repo git2::Repository) -> git2::Revwalk<'repo> {
    let mut revwalk = repo.revwalk().expect("Couldn't obtain RevWalk object for the repo");
    revwalk.set_sorting(git2::SORT_REVERSE | git2::SORT_TOPOLOGICAL);
    let head = repo.head().expect("Couldn't obtain repo's HEAD");
    let head_id = head.target().expect("Couldn't resolve repo's HEAD to a commit ID");
    // TODO: push all branches and tags, not just HEAD
    revwalk.push(head_id).expect("Couldn't add repo's HEAD to RevWalk list");

    revwalk
}

fn rewrite_repo_history(repo: &git2::Repository,
                        revwalk: &mut git2::Revwalk,
                        old_id_to_new: &mut HashMap<git2::Oid, git2::Oid>,
                        submodule_dir: &str) {
    let submodule_path = Path::new(submodule_dir);

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                // 8.1 updating the tree to contain the relevant tree from submodule
                let commit = repo.find_commit(oid)
                    .expect(&format!("Couldn't get a commit with ID {}", oid));
                let tree = commit.tree()
                    .expect(&format!("Couldn't obtain the tree of a commit with ID {}", oid));

                let submodule_subdir = match tree.get_path(submodule_path) {
                    Ok(tree) => tree,
                    Err(e) => {
                        if e.code() == git2::ErrorCode::NotFound &&
                           e.class() == git2::ErrorClass::Tree {
                            // It's okay. The tree lacks the subtree corresponding to the
                            // submodule. In other words, the commit doesn't include the submodule.
                            // That's totally fine. Let's map it into itself and move on.
                            old_id_to_new.insert(oid, oid);
                            continue;
                        } else {
                            // Unexpected error; let's report it and abort the program
                            // TODO: clean things up before aborting
                            panic!("Error getting submodule's subdir from the tree: {:?}", e);
                        };
                    }
                };

                // **INVARIANT**: if we got this far, current commit contains a submodule and
                // should be rewritten

                let submodule_commit_id = submodule_subdir.id();
                let new_submodule_commit_id = old_id_to_new[&submodule_commit_id];
                let submodule_commit = repo.find_commit(new_submodule_commit_id)
                    .expect("Couldn't obtain submodule's commit");
                let subtree_id = submodule_commit.tree()
                    .and_then(|t| t.get_path(submodule_path))
                    .and_then(|te| Ok(te.id()))
                    .expect("Couldn't obtain submodule's subtree ID");

                let mut treebuilder = repo.treebuilder(Some(&tree))
                    .expect("Couldn't create TreeBuilder");
                treebuilder.remove(submodule_path)
                    .expect("Couldn't remove submodule path from TreeBuilder");
                treebuilder.insert(submodule_path, subtree_id, 0o040000)
                    .expect("Couldn't add submodule as a subdir to TreeBuilder");
                let new_tree_id = treebuilder.write()
                    .expect("Couldn't write TreeBuilder into a Tree");
                let new_tree = repo.find_tree(new_tree_id)
                    .expect("Couldn't read back the Tree we just wrote");

                // 8.2 in commits that used to update the submodule, add a parent pointing to
                //   appropriate commit in new submodule history
                let mut parent_subtree_ids = HashSet::new();
                for parent in commit.parents() {
                    let parent_tree = parent.tree().expect("Couldn't obtain parent's tree");
                    let parent_subdir_tree_id = parent_tree.get_path(submodule_path)
                        .and_then(|x| Ok(x.id()));

                    match parent_subdir_tree_id {
                        Ok(id) => {
                            parent_subtree_ids.insert(id);
                            ()
                        }
                        Err(e) => {
                            if e.code() == git2::ErrorCode::NotFound &&
                               e.class() == git2::ErrorClass::Tree {
                                // It's okay; carry on.
                                continue;
                            } else {
                                panic!("Error getting submodule's subdir from the tree: {:?}", e);
                            };
                        }
                    }
                }
                // true if
                //
                // o--o--o--A--
                //             `,-C
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--o--A--B
                //
                // false if
                //
                // o--o--o--A--
                //             `,-A
                //  o--o--o--B-
                //
                //  or
                //
                // o--o--o--A--
                //             `,-B
                //  o--o--o--B-
                let submodule_updated: bool = !parent_subtree_ids.contains(&submodule_commit_id);

                // rewrite the parents if the submodule was updated
                let parents = {
                    let mut p: Vec<Commit> = Vec::new();
                    for parent_id in commit.parent_ids() {
                        let actual_parent_id = old_id_to_new[&parent_id];
                        let parent = repo.find_commit(actual_parent_id)
                            .expect("Couldn't find parent commit by its id");
                        p.push(parent);
                    }

                    if submodule_updated {
                        p.push(submodule_commit);
                    }

                    p
                };

                let mut parents_refs: Vec<&Commit> = Vec::new();
                for i in 0..parents.len() {
                    parents_refs.push(&parents[i]);
                }
                let new_commit_id = repo.commit(None,
                            &commit.author(),
                            &commit.committer(),
                            &commit.message().expect("Couldn't retrieve commit's message"),
                            &new_tree,
                            &parents_refs[..])
                    .expect("Failed to commit");

                old_id_to_new.insert(oid, new_commit_id);
            }
            Err(e) => eprintln!("Error walking the submodule's history: {:?}", e),
        }
    }
}

fn checkout_rewritten_history(repo: &git2::Repository,
                              old_id_to_new: &HashMap<git2::Oid, git2::Oid>) {
    let mut checkoutbuilder = CheckoutBuilder::new();
    checkoutbuilder.force();

    let head = repo.head().expect("Couldn't obtain repo's HEAD");
    let head_id = head.target().expect("Couldn't resolve repo's HEAD to a commit ID");
    let updated_id = old_id_to_new[&head_id];
    let object = repo.find_object(updated_id, None)
        .expect("Couldn't look up an object at which HEAD points");
    repo.reset(&object, git2::ResetType::Hard, Some(&mut checkoutbuilder))
        .expect("Couldn't run force-reset");
}
<|endoftext|>


<commit_before>extern crate piston_window;

use piston_window::*;

fn main() {
    let window: PistonWindow = WindowSettings::new(
            "colors",
            [600, 600]
        )
        .exit_on_esc(true)
        .build()
        .unwrap();

    let target_color = [1.0, 0.0, 0.0, 1.0];
    let mut mouse_position = (0.0, 0.0);

    for e in window {
        e.draw_2d(|c, g| {
           clear(target_color, g);

           let playing_surface = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
           playing_surface.draw([50.0, 50.0, 500.0, 500.0], &c.draw_state, c.transform, g);

           let candidate1 = Rectangle::new(target_color);
           candidate1.draw([300.0, 300.0, 100.0, 100.0], &c.draw_state, c.transform, g);

           let candidate2 = Rectangle::new([0.0, 1.0, 0.0, 1.0]);
           candidate2.draw([100.0, 200.0, 100.0, 100.0], &c.draw_state, c.transform, g);

           let candidate3 = Rectangle::new([0.0, 0.0, 1.0, 1.0]);
           candidate3.draw([300.0, 100.0, 100.0, 100.0], &c.draw_state, c.transform, g);
        });
        e.mouse_cursor(|x, y| {
            mouse_position = (x, y);
        });
        if let Some(button) = e.press_args() {
            if button == Button::Mouse(MouseButton::Left) {
                println!("press {:?}", mouse_position);
            }
        };

    }
}
<commit_msg>Extract candidates into a vec<commit_after>extern crate piston_window;

use piston_window::*;

struct Candidate {
    coordinates: [f64; 4],
    color: [f32; 4],
}

fn main() {
    let window: PistonWindow = WindowSettings::new(
            "colors",
            [600, 600]
        )
        .exit_on_esc(true)
        .build()
        .unwrap();

    let target_color = [1.0, 0.0, 0.0, 1.0];
    let mut mouse_position = (0.0, 0.0);
    let candidates = vec![
        Candidate { coordinates: [300.0, 300.0, 100.0, 100.0], color: target_color },
        Candidate { coordinates: [100.0, 200.0, 100.0, 100.0], color: [0.0, 1.0, 0.0, 1.0] },
        Candidate { coordinates: [300.0, 100.0, 100.0, 100.0], color: [0.0, 0.0, 1.0, 1.0] },
    ];

    for e in window {
        e.draw_2d(|c, g| {
           clear(target_color, g);

           let playing_surface = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
           playing_surface.draw([50.0, 50.0, 500.0, 500.0], &c.draw_state, c.transform, g);

           for candidate in &candidates {
               let r = Rectangle::new(candidate.color);
               r.draw(candidate.coordinates, &c.draw_state, c.transform, g);
           }
        });
        e.mouse_cursor(|x, y| {
            mouse_position = (x, y);
        });
        if let Some(button) = e.press_args() {
            if button == Button::Mouse(MouseButton::Left) {
                println!("press {:?}", mouse_position);
            }
        };

    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#[macro_use]
extern crate glium;

extern crate time;
extern crate image;

#[cfg(target_os = "android")]
extern crate android_glue;

mod fs;

use std::path::{Path};
use std::thread;
use std::time::Duration;
use glium::{glutin, Texture2d, DisplayBuild, Surface};
use glium::index::PrimitiveType;
use glium::glutin::ElementState::{Released};

const FPS: u64 = 60;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 2],
    tex_coords: [f32; 2],
}

implement_vertex!(Vertex, position, tex_coords);

fn load_texture<P: AsRef<Path>>(display: &glium::Display, path: P) -> Texture2d {
    let f = fs::load(path);
    let image = image::load(f, image::PNG).unwrap().to_rgba();
    let image_dimensions = image.dimensions();
    let image = glium::texture::RawImage2d::from_raw_rgba_reversed(
        image.into_raw(), image_dimensions);
    Texture2d::new(display, image).unwrap()
}

fn make_program(display: &glium::Display) -> glium::Program {
    let api = display.get_window().unwrap().get_api();
    let pre_src = fs::load_string(match api {
        glutin::Api::OpenGl => "pre_gl.glsl",
        glutin::Api::OpenGlEs => "pre_gles.glsl",
        _ => unimplemented!(),
    });
    let vs_src = pre_src.clone() + &fs::load_string("vs.glsl");
    let fs_src = pre_src + &fs::load_string("fs.glsl");
    glium::Program::from_source(display, &vs_src, &fs_src, None).unwrap()
}

fn create_display() -> glium::Display {
    let gl_version = glutin::GlRequest::GlThenGles {
        opengles_version: (2, 0),
        opengl_version: (2, 1),
    };
    glutin::WindowBuilder::new()
        .with_gl(gl_version)
        .with_depth_buffer(24)
        .with_title("Nergal".to_string())
        .build_glium()
        .unwrap()
}

struct Visualizer {
    display: glium::Display,
    program: glium::Program,
    is_running: bool,
    accumulator: u64,
    previous_clock: u64,
    vertex_buffer: glium::VertexBuffer<Vertex>,
    index_buffer: glium::IndexBuffer<u16>,
    texture: Texture2d,
}

impl Visualizer {
    fn new() -> Visualizer {
        let display = create_display();
        let program = make_program(&display);
        let vertex_buffer = {
            let vertices = [
                Vertex { position: [-0.5, -0.5], tex_coords: [0.0, 0.0] },
                Vertex { position: [-0.5,  0.5], tex_coords: [0.0, 1.0] },
                Vertex { position: [ 0.5, -0.5], tex_coords: [1.0, 0.0] },
                Vertex { position: [ 0.5,  0.5], tex_coords: [1.0, 1.0] },
            ];
            glium::VertexBuffer::new(&display, &vertices).unwrap()
        };
        let index_buffer = glium::IndexBuffer::new(
            &display, PrimitiveType::TrianglesList, &[0u16, 1, 2, 1, 2, 3]).unwrap();
        let texture = load_texture(&display, "test.png");
        let accumulator = 0;
        let previous_clock = time::precise_time_ns();
        Visualizer {
            display: display,
            program: program,
            is_running: true,
            accumulator: accumulator,
            previous_clock: previous_clock,
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            texture: texture,
        }
    }

    fn is_running(&self) -> bool {
        self.is_running
    }

    fn handle_events(&mut self) {
        let events: Vec<_> = self.display.poll_events().collect();
        for event in events {
            match event {
                // glutin::Event::Resized(x, y) => {}, // TODO
                glutin::Event::Closed => {
                    self.is_running = false;
                },
                glutin::Event::KeyboardInput(Released, _, Some(key)) => {
                    match key {
                        glutin::VirtualKeyCode::Q
                            | glutin::VirtualKeyCode::Escape =>
                        {
                            self.is_running = false;
                        },
                        _ => {},
                    }
                },
                _ => (),
            }
        }
    }

    fn draw(&self) {
        let view_matrix: [[f32; 4]; 4] = [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ];
        let uniforms = uniform! {
            matrix: view_matrix,
            texture: &self.texture,
        };
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.draw(
            &self.vertex_buffer,
            &self.index_buffer,
            &self.program,
            &uniforms,
            &Default::default(),
        ).unwrap();
        target.finish().unwrap();
    }

    fn update_timer(&mut self) {
        let fixed_time_stamp = 1_000_000_000 / FPS;
        let now = time::precise_time_ns();
        self.accumulator += now - self.previous_clock;
        self.previous_clock = now;
        while self.accumulator >= fixed_time_stamp {
            self.accumulator -= fixed_time_stamp;
            // TODO: update realtime state here
        }
        let remainder_ms = (fixed_time_stamp - self.accumulator) / 1_000_000;
        thread::sleep(Duration::from_millis(remainder_ms));
    }
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "1");
    let mut visualizer = Visualizer::new();
    while visualizer.is_running() {
        visualizer.draw();
        visualizer.handle_events();
        visualizer.update_timer();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Vertex::position: vec2 -> vec3<commit_after>// See LICENSE file for copyright and license details.

#[macro_use]
extern crate glium;

extern crate time;
extern crate image;

#[cfg(target_os = "android")]
extern crate android_glue;

mod fs;

use std::path::{Path};
use std::thread;
use std::time::Duration;
use glium::{glutin, Texture2d, DisplayBuild, Surface};
use glium::index::PrimitiveType;
use glium::glutin::ElementState::{Released};

const FPS: u64 = 60;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 3],
    tex_coords: [f32; 2],
}

implement_vertex!(Vertex, position, tex_coords);

fn load_texture<P: AsRef<Path>>(display: &glium::Display, path: P) -> Texture2d {
    let f = fs::load(path);
    let image = image::load(f, image::PNG).unwrap().to_rgba();
    let image_dimensions = image.dimensions();
    let image = glium::texture::RawImage2d::from_raw_rgba_reversed(
        image.into_raw(), image_dimensions);
    Texture2d::new(display, image).unwrap()
}

fn make_program(display: &glium::Display) -> glium::Program {
    let api = display.get_window().unwrap().get_api();
    let pre_src = fs::load_string(match api {
        glutin::Api::OpenGl => "pre_gl.glsl",
        glutin::Api::OpenGlEs => "pre_gles.glsl",
        _ => unimplemented!(),
    });
    let vs_src = pre_src.clone() + &fs::load_string("vs.glsl");
    let fs_src = pre_src + &fs::load_string("fs.glsl");
    glium::Program::from_source(display, &vs_src, &fs_src, None).unwrap()
}

fn create_display() -> glium::Display {
    let gl_version = glutin::GlRequest::GlThenGles {
        opengles_version: (2, 0),
        opengl_version: (2, 1),
    };
    glutin::WindowBuilder::new()
        .with_gl(gl_version)
        .with_depth_buffer(24)
        .with_title("Nergal".to_string())
        .build_glium()
        .unwrap()
}

struct Visualizer {
    display: glium::Display,
    program: glium::Program,
    is_running: bool,
    accumulator: u64,
    previous_clock: u64,
    vertex_buffer: glium::VertexBuffer<Vertex>,
    index_buffer: glium::IndexBuffer<u16>,
    texture: Texture2d,
}

impl Visualizer {
    fn new() -> Visualizer {
        let display = create_display();
        let program = make_program(&display);
        let vertex_buffer = {
            let vertices = [
                Vertex { position: [-0.5, -0.5, 0.0], tex_coords: [0.0, 0.0] },
                Vertex { position: [-0.5,  0.5, 0.0], tex_coords: [0.0, 1.0] },
                Vertex { position: [ 0.5, -0.5, 0.0], tex_coords: [1.0, 0.0] },
                Vertex { position: [ 0.5,  0.5, 0.0], tex_coords: [1.0, 1.0] },
            ];
            glium::VertexBuffer::new(&display, &vertices).unwrap()
        };
        let index_buffer = glium::IndexBuffer::new(
            &display, PrimitiveType::TrianglesList, &[0u16, 1, 2, 1, 2, 3]).unwrap();
        let texture = load_texture(&display, "test.png");
        let accumulator = 0;
        let previous_clock = time::precise_time_ns();
        Visualizer {
            display: display,
            program: program,
            is_running: true,
            accumulator: accumulator,
            previous_clock: previous_clock,
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            texture: texture,
        }
    }

    fn is_running(&self) -> bool {
        self.is_running
    }

    fn handle_events(&mut self) {
        let events: Vec<_> = self.display.poll_events().collect();
        for event in events {
            match event {
                // glutin::Event::Resized(x, y) => {}, // TODO
                glutin::Event::Closed => {
                    self.is_running = false;
                },
                glutin::Event::KeyboardInput(Released, _, Some(key)) => {
                    match key {
                        glutin::VirtualKeyCode::Q
                            | glutin::VirtualKeyCode::Escape =>
                        {
                            self.is_running = false;
                        },
                        _ => {},
                    }
                },
                _ => (),
            }
        }
    }

    fn draw(&self) {
        let view_matrix: [[f32; 4]; 4] = [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ];
        let uniforms = uniform! {
            matrix: view_matrix,
            texture: &self.texture,
        };
        let mut target = self.display.draw();
        target.clear_color(0.0, 0.0, 0.0, 0.0);
        target.draw(
            &self.vertex_buffer,
            &self.index_buffer,
            &self.program,
            &uniforms,
            &Default::default(),
        ).unwrap();
        target.finish().unwrap();
    }

    fn update_timer(&mut self) {
        let fixed_time_stamp = 1_000_000_000 / FPS;
        let now = time::precise_time_ns();
        self.accumulator += now - self.previous_clock;
        self.previous_clock = now;
        while self.accumulator >= fixed_time_stamp {
            self.accumulator -= fixed_time_stamp;
            // TODO: update realtime state here
        }
        let remainder_ms = (fixed_time_stamp - self.accumulator) / 1_000_000;
        thread::sleep(Duration::from_millis(remainder_ms));
    }
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "1");
    let mut visualizer = Visualizer::new();
    while visualizer.is_running() {
        visualizer.draw();
        visualizer.handle_events();
        visualizer.update_timer();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>//! Yet Another Brainfuck Interpreter in Rust.

pub mod cli;
pub mod lexer;
pub mod loader;
pub mod parser;
pub mod runner;

use std::io::Write;

fn main() {
    let args = cli::get_args();
    if cli::should_print_usage(&args) {
        cli::print_usage();
        std::process::exit(0);
    }

    run_prog(&args[0]).unwrap_or_else(|err| {
        print_error(&err);
        std::process::exit(1);
    })
}

fn run_prog(prog_path: &String) -> Result<(), String> {
    let prog = loader::load_prog(&prog_path)?;
    let prog_tokens = lexer::tokenize(&prog);
    let prog_ops = parser::parse(&prog_tokens)?;
    let mut input = std::io::stdin();
    let mut output = std::io::stdout();
    runner::run(prog_ops, &mut input, &mut output)
}

fn print_error(err: &String) {
    writeln!(&mut std::io::stderr(), "error: {}", err)
        .expect("failed printing an error");
}
<commit_msg>Make error checking in main() more readable.<commit_after>//! Yet Another Brainfuck Interpreter in Rust.

pub mod cli;
pub mod lexer;
pub mod loader;
pub mod parser;
pub mod runner;

use std::io::Write;

fn main() {
    let args = cli::get_args();
    if cli::should_print_usage(&args) {
        cli::print_usage();
        std::process::exit(0);
    }

    if let Err(err) = run_prog(&args[0]) {
        print_error(&err);
        std::process::exit(1);
    }
}

fn run_prog(prog_path: &String) -> Result<(), String> {
    let prog = loader::load_prog(&prog_path)?;
    let prog_tokens = lexer::tokenize(&prog);
    let prog_ops = parser::parse(&prog_tokens)?;
    let mut input = std::io::stdin();
    let mut output = std::io::stdout();
    runner::run(prog_ops, &mut input, &mut output)
}

fn print_error(err: &String) {
    writeln!(&mut std::io::stderr(), "error: {}", err)
        .expect("failed printing an error");
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::num::Int;

pub fn main() {
    let rows = 14;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut collisions: HashMap<String,Vec<u64>> = HashMap::new();

    // TODO random bytes
    for bytes in range(0u64, 256u64.pow(16 - rows)) {
        // TODO set bytes
        let mut shift = (16 - rows - 1) * 8;
        for col in range(17, 17 + 16 - rows) {
            values[rows][col] = (bytes >> shift) as u8;
            values[rows][col + 16] = (bytes >> shift) as u8;
            shift -= 8;
        }

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        // TODO use byte string?
        let key = range(rows + 2, 19).fold(String::new(), |acc, row| {
          format!("{}{:02x}", acc, values[row][0])
        });

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes)); },
            Occupied(mut entry) => { entry.get_mut().push(bytes); }
        };
    }

    // Compute original messages for each collision.
    let mut count = 0u;
    for collision in collisions.values().filter(|x| x.len() > 1) {
        count += 1;
        for bytes in collision.iter() {
            // TODO set bytes
            let mut shift = (16 - rows - 1) * 8;
            for col in range(17, 17 + 16 - rows) {
                values[rows][col] = (*bytes >> shift) as u8;
                values[rows][col + 16] = (*bytes >> shift) as u8;
                shift -= 8;
            }

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            let empty = [0u8, ..16];
            let msg = values[0].slice(17, 33).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            let hash = md2_compress(&empty, values[0].slice(17, 33)).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            println!("msg = {}, hash = {}", msg, hash);
        }

        println!("");
    }

    println!("Found {} collisions.", count);
}
<commit_msg>use a vector as hashmap key<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::num::Int;

pub fn main() {
    let rows = 14;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut collisions: HashMap<Vec<u8>,Vec<u64>> = HashMap::new();

    // TODO random bytes
    for bytes in range(0u64, 256u64.pow(16 - rows)) {
        // TODO set bytes
        let mut shift = (16 - rows - 1) * 8;
        for col in range(17, 17 + 16 - rows) {
            values[rows][col] = (bytes >> shift) as u8;
            values[rows][col + 16] = (bytes >> shift) as u8;
            shift -= 8;
        }

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes)); },
            Occupied(mut entry) => { entry.get_mut().push(bytes); }
        };
    }

    // Compute original messages for each collision.
    let mut count = 0u;
    for collision in collisions.values().filter(|x| x.len() > 1) {
        count += 1;
        for bytes in collision.iter() {
            // TODO set bytes
            let mut shift = (16 - rows - 1) * 8;
            for col in range(17, 17 + 16 - rows) {
                values[rows][col] = (*bytes >> shift) as u8;
                values[rows][col + 16] = (*bytes >> shift) as u8;
                shift -= 8;
            }

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            let empty = [0u8, ..16];
            let msg = values[0].slice(17, 33).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            let hash = md2_compress(&empty, values[0].slice(17, 33)).iter().fold(String::new(), |a, &b| format!("{}{:02x}", a, b));
            println!("msg = {}, hash = {}", msg, hash);
        }

        println!("");
    }

    println!("Found {} collisions.", count);
}
<|endoftext|>


<commit_before>// This should fail to compile if any of these code examples are wrong.

fn main() {
    // Doing the string conversions all in main so that the lifetimes can be inferred.

    let s = "I am a &str.";

    // &str => String
    let st: String = s.to_string();

    // String => &str
    let str: &str = st.as_slice();
}

// int ---------------------------------------------------------------

fn int_to_uint(x: int) -> uint {
    x as uint
}

#[test]
fn test_int_to_uint_happy() {
    let x = 3i;
    let y = 3u;
    assert_eq!(y, int_to_uint(x));
}

fn int_to_string(x: int) -> String {
    x.to_string()
}

#[test]
fn test_int_to_string_happy() {
    let x = 3i;
    let y = "3";
    assert_eq!(y, int_to_string(x));
}

fn int_to_char(x: int) -> char {
    std::char::from_digit(x.to_uint().unwrap(), 10).unwrap()
}

#[test]
fn test_int_to_char_happy() {
    let x = 3i;
    let y = '3';
    assert_eq!(y, int_to_char(x));
}

// uint ---------------------------------------------------------------

fn uint_to_int(x: uint) -> int {
    x as int
}

#[test]
fn test_uint_to_int_happy() {
    let x = 3u;
    let y = 3i;
    assert_eq!(y, uint_to_int(x));
}

fn uint_to_string(x: uint) -> String {
    x.to_string()
}

#[test]
fn test_uint_to_string_happy() {
    let x = 3u;
    let y = "3";
    assert_eq!(y, uint_to_string(x));
}

fn uint_to_char(x: uint) -> char {
    std::char::from_digit(x, 10).unwrap()
}

#[test]
fn test_uint_to_char_happy() {
    let x = 3u;
    let y = '3';
    assert_eq!(y, uint_to_char(x));
}

// String ---------------------------------------------------------------

fn string_to_int(x: String) -> int {
    x.parse::<int>().unwrap()
}

#[test]
fn test_string_to_int_happy() {
    let x = "3".to_string();
    let y = 3i;
    assert_eq!(y, string_to_int(x));
}

fn string_to_uint(x: String) -> uint {
    x.parse::<uint>().unwrap()
}

#[test]
fn test_string_to_uint_happy() {
    let x = "3".to_string();
    let y = 3u;
    assert_eq!(y, string_to_uint(x));
}

fn string_to_char(x: String) -> char {
    x.char_at(0)
}

#[test]
fn test_string_to_char_happy() {
    let x = "3".to_string();
    let y = '3';
    assert_eq!(y, string_to_char(x));
}

// char ---------------------------------------------------------------

fn char_to_int(x: char) -> int {
    std::char::to_digit(x, 10).unwrap().to_int().unwrap()
}

#[test]
fn test_char_to_int_happy() {
    let x = '3';
    let y = 3i;
    assert_eq!(y, char_to_int(x));
}

fn char_to_uint(x: char) -> uint {
    std::char::to_digit(x, 10).unwrap()
}

#[test]
fn test_char_to_uint_happy() {
    let x = '3';
    let y = 3u;
    assert_eq!(y, char_to_uint(x));
}

fn char_to_string(x: char) -> String {
    x.to_string()
}

#[test]
fn test_char_to_string_happy() {
    let x = '3';
    let y = "3";
    assert_eq!(y, char_to_string(x));
}
<commit_msg>Hide dead code warnings to better see other warnings<commit_after>// This should fail to compile if any of these code examples are wrong.

#[allow(dead_code)]
fn main() {
    // Doing the string conversions all in main so that the lifetimes can be inferred.

    let s = "I am a &str.";

    // &str => String
    let st: String = s.to_string();

    // String => &str
    let str: &str = st.as_slice();
}

// int ---------------------------------------------------------------
#[allow(dead_code)]
fn int_to_uint(x: int) -> uint {
    x as uint
}

#[test]
fn test_int_to_uint_happy() {
    let x = 3i;
    let y = 3u;
    assert_eq!(y, int_to_uint(x));
}

#[allow(dead_code)]
fn int_to_string(x: int) -> String {
    x.to_string()
}

#[test]
fn test_int_to_string_happy() {
    let x = 3i;
    let y = "3";
    assert_eq!(y, int_to_string(x));
}

#[allow(dead_code)]
fn int_to_char(x: int) -> char {
    std::char::from_digit(x.to_uint().unwrap(), 10).unwrap()
}

#[test]
fn test_int_to_char_happy() {
    let x = 3i;
    let y = '3';
    assert_eq!(y, int_to_char(x));
}

// uint ---------------------------------------------------------------

#[allow(dead_code)]
fn uint_to_int(x: uint) -> int {
    x as int
}

#[test]
fn test_uint_to_int_happy() {
    let x = 3u;
    let y = 3i;
    assert_eq!(y, uint_to_int(x));
}

#[allow(dead_code)]
fn uint_to_string(x: uint) -> String {
    x.to_string()
}

#[test]
fn test_uint_to_string_happy() {
    let x = 3u;
    let y = "3";
    assert_eq!(y, uint_to_string(x));
}

#[allow(dead_code)]
fn uint_to_char(x: uint) -> char {
    std::char::from_digit(x, 10).unwrap()
}

#[test]
fn test_uint_to_char_happy() {
    let x = 3u;
    let y = '3';
    assert_eq!(y, uint_to_char(x));
}

// String ---------------------------------------------------------------

#[allow(dead_code)]
fn string_to_int(x: String) -> int {
    x.parse::<int>().unwrap()
}

#[test]
fn test_string_to_int_happy() {
    let x = "3".to_string();
    let y = 3i;
    assert_eq!(y, string_to_int(x));
}

#[allow(dead_code)]
fn string_to_uint(x: String) -> uint {
    x.parse::<uint>().unwrap()
}

#[test]
fn test_string_to_uint_happy() {
    let x = "3".to_string();
    let y = 3u;
    assert_eq!(y, string_to_uint(x));
}

#[allow(dead_code)]
fn string_to_char(x: String) -> char {
    x.char_at(0)
}

#[test]
fn test_string_to_char_happy() {
    let x = "3".to_string();
    let y = '3';
    assert_eq!(y, string_to_char(x));
}

// char ---------------------------------------------------------------

#[allow(dead_code)]
fn char_to_int(x: char) -> int {
    std::char::to_digit(x, 10).unwrap().to_int().unwrap()
}

#[test]
fn test_char_to_int_happy() {
    let x = '3';
    let y = 3i;
    assert_eq!(y, char_to_int(x));
}

#[allow(dead_code)]
fn char_to_uint(x: char) -> uint {
    std::char::to_digit(x, 10).unwrap()
}

#[test]
fn test_char_to_uint_happy() {
    let x = '3';
    let y = 3u;
    assert_eq!(y, char_to_uint(x));
}

#[allow(dead_code)]
fn char_to_string(x: char) -> String {
    x.to_string()
}

#[test]
fn test_char_to_string_happy() {
    let x = '3';
    let y = "3";
    assert_eq!(y, char_to_string(x));
}
<|endoftext|>


<commit_before>extern crate waitgroup;
use std::sync::Arc;
use std::thread;
fn main() {
    let wg = Arc::new(waitgroup::WaitGroup::new());
    wg.add(1);
    let wg2 = wg.clone();
    thread::spawn(move|| {
        thread::sleep_ms(3000);
        wg2.done();
    });
    wg.wait();
    println!("done")
}
<commit_msg>better example<commit_after>extern crate waitgroup;
use std::sync::Arc;
use std::thread;
fn main() {
    let wg = Arc::new(waitgroup::WaitGroup::new());
    for i in 0..100 {
        wg.add(1);
        let wg2 = wg.clone();
        thread::spawn(move|| {
            thread::sleep_ms(2000);
            wg2.done();
        });
    }
    wg.wait();
    println!("done")
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate ansi_term;
extern crate clap;

use hyper::client::Client;
use std::io::Read;
use std::string::String;
use ansi_term::Colour::{Red, Green, Yellow, Cyan};
use std::process::Command;
use std::process::Stdio;
use std::cmp::Ordering;
use clap::{Arg, App, AppSettings, SubCommand};

struct Server {
    protocol: String,
    players: u8,
    observers: u8,
    address: String,
    name: String,
}

fn main() {
    let args = App::new("bzls-rust")
        .version("0.1.0")
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("all")
            .short("a")
            .long("all")
            .help("Lists all servers, even those with no players"))
        .arg(Arg::with_name("reverse")
            .short("r")
            .long("reverse")
            .help("Reverses result order"))
        .arg(Arg::with_name("no_stats")
            .short("s")
            .long("no-stats")
            .help("Don't display overall stats in the end of the list"))
        .arg(Arg::with_name("length")
            .short("l")
            .long("length")
            .value_name("N")
            .help("The length of the server name"))
        .arg(Arg::with_name("SEARCH")
            .index(1)
            .help("An address to search for"))
        .get_matches();
    let show_all = args.is_present("all");
    let search = args.value_of("SEARCH");

    let mut servers: Vec<Server> = Vec::new();

    let client = Client::new();

    let mut res = client.get("https://my.bzflag.org/db/?action=LIST&listformat=plain").send().unwrap();
    assert_eq!(res.status, hyper::Ok);

    let mut data = String::new();
    res.read_to_string(&mut data).expect("Failed to read data");

    for line in data.lines() {
        let server: Vec<&str> = line.split(' ').collect();

        let data = server[2];
        let players = [
            u8::from_str_radix(&data[34..36], 16).unwrap(), // rogue
            u8::from_str_radix(&data[38..40], 16).unwrap(), // red
            u8::from_str_radix(&data[42..44], 16).unwrap(), // green
            u8::from_str_radix(&data[46..48], 16).unwrap(), // blue
            u8::from_str_radix(&data[50..52], 16).unwrap(), // purple
        ];
        let players: u8 = players.iter().fold(0u8, |a, &b| a + b);
        let observers = u8::from_str_radix(&data[54..56], 16).unwrap();

        let server = Server {
            protocol: server[1].to_string(),
            players: players,
            observers: observers,
            address: server[0].to_string(),
            name: (&server[4..]).join(" ").to_string()
        };

        servers.push(server);
    }

    let server_count = servers.len();

    servers.sort_by(|a, b| match b.players.cmp(&a.players) {
        Ordering::Equal => b.observers.cmp(&a.observers),
        c => c
    });

    if args.is_present("reverse") {
        servers.reverse();
    }

    let cols:usize = match args.value_of("length") {
        None => match Command::new("stty").arg("size").arg("-F").arg("/dev/stderr").stderr(Stdio::inherit()).output() {
            Ok(out) => String::from_utf8(out.stdout).unwrap().split_whitespace().last().unwrap().parse().unwrap(),
            Err(_) => 80,
        },
        Some(l) => l.parse().expect("Please enter a valid length value")
    };

    let mut playing_count: u16 = 0;
    let mut player_count: u32 = 0;

    for server in servers {
        if server.players == 0 && !show_all {
            continue;
        }

        if search.is_some() && !server.address.contains(search.unwrap()) {
            continue;
        }

        if server.players != 0 {
            playing_count += 1;
            player_count += server.players as u32;
        }

        println!("[{}, {}]  {}  {}",
            Yellow.paint(format!("{:2}", server.players)),
            Cyan.paint(server.observers.to_string()),
            Green.paint(format!("{:1$}", server.name, cols/3)),
            Red.paint(server.address)
        );
    }

    if !args.is_present("no_stats") {
        println!("\n{} active server{}, {} server{} found, {} player{} total",
            playing_count, if playing_count != 1 { "s" } else { "" },
            server_count, if server_count != 1 { "s" } else { "" },
            player_count, if player_count != 1 { "s" } else { "" }
        );
    }
}
<commit_msg>Allow searching if the server address starts with a string<commit_after>extern crate hyper;
extern crate ansi_term;
extern crate clap;

use hyper::client::Client;
use std::io::Read;
use std::string::String;
use ansi_term::Colour::{Red, Green, Yellow, Cyan};
use std::process::Command;
use std::process::Stdio;
use std::cmp::Ordering;
use clap::{Arg, App, AppSettings, SubCommand};

struct Server {
    protocol: String,
    players: u8,
    observers: u8,
    address: String,
    name: String,
}

fn main() {
    let args = App::new("bzls-rust")
        .version("0.1.0")
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("all")
            .short("a")
            .long("all")
            .help("Lists all servers, even those with no players"))
        .arg(Arg::with_name("reverse")
            .short("r")
            .long("reverse")
            .help("Reverses result order"))
        .arg(Arg::with_name("no_stats")
            .short("s")
            .long("no-stats")
            .help("Don't display overall stats in the end of the list"))
        .arg(Arg::with_name("length")
            .short("l")
            .long("length")
            .value_name("N")
            .help("The length of the server name"))
        .arg(Arg::with_name("SEARCH")
            .index(1)
            .help("An address to search for"))
        .get_matches();
    let show_all = args.is_present("all");
    let search = args.value_of("SEARCH");

    let mut servers: Vec<Server> = Vec::new();

    let client = Client::new();

    let mut res = client.get("https://my.bzflag.org/db/?action=LIST&listformat=plain").send().unwrap();
    assert_eq!(res.status, hyper::Ok);

    let mut data = String::new();
    res.read_to_string(&mut data).expect("Failed to read data");

    for line in data.lines() {
        let server: Vec<&str> = line.split(' ').collect();

        let data = server[2];
        let players = [
            u8::from_str_radix(&data[34..36], 16).unwrap(), // rogue
            u8::from_str_radix(&data[38..40], 16).unwrap(), // red
            u8::from_str_radix(&data[42..44], 16).unwrap(), // green
            u8::from_str_radix(&data[46..48], 16).unwrap(), // blue
            u8::from_str_radix(&data[50..52], 16).unwrap(), // purple
        ];
        let players: u8 = players.iter().fold(0u8, |a, &b| a + b);
        let observers = u8::from_str_radix(&data[54..56], 16).unwrap();

        let server = Server {
            protocol: server[1].to_string(),
            players: players,
            observers: observers,
            address: server[0].to_string(),
            name: (&server[4..]).join(" ").to_string()
        };

        servers.push(server);
    }

    let server_count = servers.len();

    servers.sort_by(|a, b| match b.players.cmp(&a.players) {
        Ordering::Equal => b.observers.cmp(&a.observers),
        c => c
    });

    if args.is_present("reverse") {
        servers.reverse();
    }

    let cols:usize = match args.value_of("length") {
        None => match Command::new("stty").arg("size").arg("-F").arg("/dev/stderr").stderr(Stdio::inherit()).output() {
            Ok(out) => String::from_utf8(out.stdout).unwrap().split_whitespace().last().unwrap().parse().unwrap(),
            Err(_) => 80,
        },
        Some(l) => l.parse().expect("Please enter a valid length value")
    };

    let mut playing_count: u16 = 0;
    let mut player_count: u32 = 0;

    for server in servers {
        if server.players == 0 && !show_all {
            continue;
        }

        if search.is_some() {
            // We are searching for a string
            let searching = search.unwrap();

            let last_char = searching.chars().rev().next().unwrap();
            if last_char == ':' && !server.address.starts_with(searching) {
                // If the last character is a :, make sure our string starts
                // with the search query, without having any other characters
                // before
                continue;
            } else if last_char != ':' && !server.address.contains(searching) {
                continue;
            }
        }

        if server.players != 0 {
            playing_count += 1;
            player_count += server.players as u32;
        }

        println!("[{}, {}]  {}  {}",
            Yellow.paint(format!("{:2}", server.players)),
            Cyan.paint(server.observers.to_string()),
            Green.paint(format!("{:1$}", server.name, cols/3)),
            Red.paint(server.address)
        );
    }

    if !args.is_present("no_stats") {
        println!("\n{} active server{}, {} server{} found, {} player{} total",
            playing_count, if playing_count != 1 { "s" } else { "" },
            server_count, if server_count != 1 { "s" } else { "" },
            player_count, if player_count != 1 { "s" } else { "" }
        );
    }
}
<|endoftext|>


<commit_before>
#![feature(io)]

use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::sync::{ Arc, Mutex, MutexGuard };
use std::sync::mpsc::{ channel, Sender, Receiver };
use std::thread;

// State Function
struct StateFn<E: std::error::Error>(fn(l: &mut Lex<E>)->Option<StateFn<E>>);

#[derive(Debug)]
struct Pos {
    pos: u64,
    line: u64,
    col: u64
}

// Position
impl Pos {
    fn new()->Pos {
        Pos {
            pos: 0,
            line: 0,
            col: 0
        }
    }

    fn next(&mut self, c: char) {
        self.pos += 1;
        match c {
            '\n' => {
                self.line += 1;
                self.col = 0;
            },
            _ => self.col += 1
        }
    }

    fn back(&mut self, c: char) {
        self.pos -= 1;
        match c {
            // Don't back over newlines.
            _ => self.col -= 1
        }
    }
}

#[derive(Debug)]
enum TokenType {
    Integer,
    Operator
}

#[derive(Debug)]
struct Token {
    pos: Pos,
    typ: TokenType,
    val: String
}

trait Lex<E: std::error::Error> {
    fn next(&mut self)->Result<char, E>;
    fn back(&mut self);
    fn emit(&mut self);
}

// State Machine
struct Lexer<R: io::Read+Send> {
    // Current position
    pos: Pos,
    // Input character stream
    input: Arc<Mutex<io::Chars<R>>>,
    // Back buffer
    backbuf: Vec<char>,
    // Unemitted buffer
    buf: Vec<char>,
    // State machine position
    state: StateFn<io::CharsError>,
    // Sending handle to token channel
    send: Option<Sender<Token>>,
    // Sending state machine thread handle
    handle: Option<thread::JoinHandle<()>>
}

fn start_state<E: std::error::Error>(l: &mut Lex<E>)->Option<StateFn<E>> {
    l.emit();
    None
}

impl<R: io::Read+Send+'static> Lexer<R> {
    fn new(reader: R)->Lexer<R> {
        let mut l = Lexer {
            pos: Pos::new(),
            input: Arc::new(Mutex::new(reader.chars())),
            buf: Vec::<char>::new(),
            backbuf: Vec::<char>::new(),
            state: StateFn(start_state),
            send: None,
            handle: None,
        };
        l
    }

    fn spawn(mut self)->Receiver<Token> {
        let (tx, rx) = channel();
        self.send = Some(tx);
        self.handle = Some(thread::spawn(move || {
            loop {
                match (self.state.0)(&mut self) {
                    Some(s) => self.state = s,
                    None => return
                }
            }
        }));
        rx
    }
}

impl<R: io::Read+Send> Lex<io::CharsError> for Lexer<R> {
    fn next(&mut self)->Result<char, io::CharsError> {
        let c = if self.backbuf.len() == 0 {
            'h'
            // self.input.lock().unwrap().next().unwrap()
        } else {
            self.backbuf.pop().unwrap()
        };
        self.buf.push(c); // Push to unemitted buffer
        self.pos.next(c); // Update position
        Ok(c)
    }

    fn back(&mut self) {
        self.buf.push(self.backbuf.pop().unwrap())
    }

    fn emit(&mut self) {
        self.send.as_ref().unwrap().send(Token{
            pos: Pos::new(),
            typ: TokenType::Integer,
            val: "Test".to_string()
        }).unwrap();
    }
}

fn main() {
    let lexer = Lexer::new(BufReader::new(File::open("src.f").unwrap()));
    let rx = lexer.spawn();
    println!("{:?}", rx.recv().unwrap());
}
<commit_msg>spaces to tabs<commit_after>
#![feature(io)]

use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::sync::{ Arc, Mutex, MutexGuard };
use std::sync::mpsc::{ channel, Sender, Receiver };
use std::thread;

// State Function
struct StateFn<E: std::error::Error>(fn(l: &mut Lex<E>)->Option<StateFn<E>>);

#[derive(Debug)]
struct Pos {
	pos: u64,
	line: u64,
	col: u64
}

// Position
impl Pos {
	fn new()->Pos {
		Pos {
			pos: 0,
			line: 0,
			col: 0
		}
	}

	fn next(&mut self, c: char) {
		self.pos += 1;
		match c {
			'\n' => {
				self.line += 1;
				self.col = 0;
			},
			_ => self.col += 1
		}
	}

	fn back(&mut self, c: char) {
		self.pos -= 1;
		match c {
			// Don't back over newlines.
			_ => self.col -= 1
		}
	}
}

#[derive(Debug)]
enum TokenType {
	Integer,
	Operator
}

#[derive(Debug)]
struct Token {
	pos: Pos,
	typ: TokenType,
	val: String
}

trait Lex<E: std::error::Error> {
	fn next(&mut self)->Result<char, E>;
	fn back(&mut self);
	fn emit(&mut self);
}

// State Machine
struct Lexer<R: io::Read+Send> {
	// Current position
	pos: Pos,
	// Input character stream
	input: Arc<Mutex<io::Chars<R>>>,
	// Back buffer
	backbuf: Vec<char>,
	// Unemitted buffer
	buf: Vec<char>,
	// State machine position
	state: StateFn<io::CharsError>,
	// Sending handle to token channel
	send: Option<Sender<Token>>,
	// Sending state machine thread handle
	handle: Option<thread::JoinHandle<()>>
}

fn start_state<E: std::error::Error>(l: &mut Lex<E>)->Option<StateFn<E>> {
	l.emit();
	None
}

impl<R: io::Read+Send+'static> Lexer<R> {
	fn new(reader: R)->Lexer<R> {
		let mut l = Lexer {
			pos: Pos::new(),
			input: Arc::new(Mutex::new(reader.chars())),
			buf: Vec::<char>::new(),
			backbuf: Vec::<char>::new(),
			state: StateFn(start_state),
			send: None,
			handle: None,
		};
		l
	}

	fn spawn(mut self)->Receiver<Token> {
		let (tx, rx) = channel();
		self.send = Some(tx);
		self.handle = Some(thread::spawn(move || {
			loop {
				match (self.state.0)(&mut self) {
					Some(s) => self.state = s,
					None => return
				}
			}
		}));
		rx
	}
}

impl<R: io::Read+Send> Lex<io::CharsError> for Lexer<R> {
	fn next(&mut self)->Result<char, io::CharsError> {
		let c = if self.backbuf.len() == 0 {
			'h'
			// self.input.lock().unwrap().next().unwrap()
		} else {
			self.backbuf.pop().unwrap()
		};
		self.buf.push(c); // Push to unemitted buffer
		self.pos.next(c); // Update position
		Ok(c)
	}

	fn back(&mut self) {
		self.buf.push(self.backbuf.pop().unwrap())
	}

	fn emit(&mut self) {
		self.send.as_ref().unwrap().send(Token{
			pos: Pos::new(),
			typ: TokenType::Integer,
			val: "Test".to_string()
		}).unwrap();
	}
}

fn main() {
	let lexer = Lexer::new(BufReader::new(File::open("src.f").unwrap()));
	let rx = lexer.spawn();
	println!("{:?}", rx.recv().unwrap());
}
<|endoftext|>


<commit_before>use std::io;

extern crate clap;
#[macro_use]
extern crate log;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate syn;
extern crate toml;

use clap::{Arg, App};

mod logging;
mod bindgen;

use bindgen::{Config, Library};

fn main() {
    let matches = App::new("cbindgen")
                    .version(bindgen::VERSION)
                    .about("Generate C bindings for a Rust library")
                    .arg(Arg::with_name("config")
                         .short("c")
                         .long("config")
                         .value_name("CONFIG")
                         .help("the config to use. currently either `wr`, or `default`"))
                    .arg(Arg::with_name("v")
                         .short("v")
                         .help("whether to print verbose logs"))
                    .arg(Arg::with_name("INPUT")
                         .help("the crate or source file to generate bindings for")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("OUTPUT")
                         .help("the path to output the directories to")
                         .required(false)
                         .index(2))
                    .get_matches();

    if matches.is_present("v") {
        logging::InfoLogger::init().unwrap();
    } else {
        logging::WarnLogger::init().unwrap();
    }

    let input = matches.value_of("INPUT").unwrap();

    let config = match matches.value_of("config") {
        Some(c) => Config::load(c),
        None => Config::from_root_or_default(&input),
    };

    let built = match Library::load(input, &config).generate() {
        Ok(x) => x,
        Err(msg) => {
            error!("{}", msg);
            error!("could not generate bindings for {}", input);
            return;
        },
    };

    match matches.value_of("OUTPUT") {
        Some(file) => {
            built.write_to_file(file);
        }
        _ => {
            built.write(&mut io::stdout());
        }
    }
}
<commit_msg>Put output behind a commandline flag<commit_after>use std::io;

extern crate clap;
#[macro_use]
extern crate log;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate syn;
extern crate toml;

use clap::{Arg, App};

mod logging;
mod bindgen;

use bindgen::{Config, Library};

fn main() {
    let matches = App::new("cbindgen")
                    .version(bindgen::VERSION)
                    .about("Generate C bindings for a Rust library")
                    .arg(Arg::with_name("config")
                         .short("c")
                         .long("config")
                         .value_name("CONFIG")
                         .help("the config to use. currently either `wr`, or `default`"))
                    .arg(Arg::with_name("v")
                         .short("v")
                         .help("whether to print verbose logs"))
                    .arg(Arg::with_name("INPUT")
                         .help("the crate or source file to generate bindings for")
                         .required(true)
                         .index(1))
                    .arg(Arg::with_name("out")
                         .short("o")
                         .long("output")
                         .value_name("OUTPUT")
                         .help("the path to output the bindings to")
                         .required(false))
                    .get_matches();

    if matches.is_present("v") {
        logging::InfoLogger::init().unwrap();
    } else {
        logging::WarnLogger::init().unwrap();
    }

    let input = matches.value_of("INPUT").unwrap();

    let config = match matches.value_of("config") {
        Some(c) => Config::load(c),
        None => Config::from_root_or_default(&input),
    };

    let built = match Library::load(input, &config).generate() {
        Ok(x) => x,
        Err(msg) => {
            error!("{}", msg);
            error!("could not generate bindings for {}", input);
            return;
        },
    };

    match matches.value_of("out") {
        Some(file) => {
            built.write_to_file(file);
        }
        _ => {
            built.write(&mut io::stdout());
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate libc;
extern crate notify;

mod notification_filter;

use std::sync::mpsc::{channel, Receiver, RecvError};
use std::{env, io, thread, time};
use std::process::{Child, Command};

use clap::{App, Arg};
use notify::{Event, RecommendedWatcher, Watcher};

use notification_filter::NotificationFilter;

fn clear() {
    // TODO: determine better way to do this
    let clear_cmd;
    if cfg!(target_os = "windows") {
        clear_cmd = "cls";
    }
    else {
        clear_cmd = "clear";
    }

    let _ = Command::new(clear_cmd).status();
}

fn invoke(cmd: &str) -> io::Result<Child> {
    if cfg!(target_os = "windows") {
        Command::new("cmd.exe")
                .arg("/C")
                .arg(cmd)
                .spawn()
    }
    else {
        Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .spawn()
    }
}

fn wait(rx: &Receiver<Event>, filter: &NotificationFilter, verbose: bool) -> Result<Event, RecvError> {
    loop {
        // Block on initial notification
        let e = try!(rx.recv());
        if let Some(ref path) = e.path {
            if filter.is_excluded(&path) {
                if verbose {
                    println!("*** Ignoring {} due to filter", path.to_str().unwrap());
                }
                continue;
            }
        }

        // Accumulate subsequent events
        thread::sleep(time::Duration::from_millis(250));

        // Drain rx buffer and drop them
        loop {
            match rx.try_recv() {
                Ok(_) => continue,
                Err(_) => break,
            }
        }

        return Ok(e);
    }
}

fn main() {
    let args = App::new("watchexec")
        .version("0.10.0")
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("path")
            .help("Path to watch")
            .short("w")
            .long("watch")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true)
            .default_value("."))
        .arg(Arg::with_name("command")
            .help("Command to execute")
            .multiple(true)
            .required(true))
        .arg(Arg::with_name("extensions")
             .help("Comma-separated list of file extensions to watch (js,css,html)")
             .short("e")
             .long("exts")
             .takes_value(true))
        .arg(Arg::with_name("clear")
            .help("Clear screen before executing command")
            .short("c")
            .long("clear"))
        .arg(Arg::with_name("restart")
             .help("Restart the process if it's still running")
             .short("r")
             .long("restart"))
        .arg(Arg::with_name("verbose")
             .help("Prints diagnostic messages")
             .short("v")
             .long("verbose"))
        .arg(Arg::with_name("filter")
             .help("Ignore all modifications except those matching the pattern")
             .short("f")
             .long("filter")
             .number_of_values(1)
             .multiple(true)
             .takes_value(true)
             .value_name("pattern"))
        .arg(Arg::with_name("ignore")
             .help("Ignore modifications to paths matching the pattern")
             .short("i")
             .long("ignore")
             .number_of_values(1)
             .multiple(true)
             .takes_value(true)
             .value_name("pattern"))
        .get_matches();

    let verbose = args.is_present("verbose");

    let cwd = env::current_dir().unwrap();
    let mut filter = NotificationFilter::new(&cwd);

    // Ignore python bytecode and dotted directories by default
    let default_filters = vec!["*.pyc", ".*/*"];
    for p in default_filters {
        filter.add_ignore(p).expect("bad default filter");
    }

    if let Some(extensions) = args.values_of("extensions") {
        for ext in extensions {
            filter.add_extension(ext).expect("bad extension");
        }
    }

    if let Some(filters) = args.values_of("filter") {
        for p in filters {
            filter.add_filter(p).expect("bad filter");
        }
    }

    if let Some(ignores) = args.values_of("ignore") {
        for i in ignores {
            filter.add_ignore(i).expect("bad ignore pattern");
        }
    }

    let (tx, rx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(tx).expect("unable to create watcher");

    let paths = args.values_of("path").unwrap();
    for path in paths {
        watcher.watch(path).expect("unable to watch path");
    }

    let cmd_parts: Vec<&str> = args.values_of("command").unwrap().collect();
    let cmd = cmd_parts.join(" ");
    let restart = args.is_present("restart");
    let mut child_process: Option<Child> = None;

    loop {
        let e = wait(&rx, &filter, verbose).expect("error when waiting for filesystem changes");

        if let Some(mut child) = child_process {
            if restart {
                let _ = child.kill();
            }

            let _ = child.wait();
        }

        if args.is_present("clear") {
            clear();
        }

        if verbose {
            println!("*** {:?}: {:?}", e.op, e.path);
        }

        if verbose {
            println!("*** Executing: {}", cmd);
        }

        child_process = invoke(&cmd).ok();
    }
}
<commit_msg>Platform-agnostic dotted dir ignore<commit_after>extern crate clap;
extern crate libc;
extern crate notify;

mod notification_filter;

use std::sync::mpsc::{channel, Receiver, RecvError};
use std::{env, io, thread, time};
use std::path::Path;
use std::process::{Child, Command};

use clap::{App, Arg};
use notify::{Event, RecommendedWatcher, Watcher};

use notification_filter::NotificationFilter;

fn clear() {
    // TODO: determine better way to do this
    let clear_cmd;
    if cfg!(target_os = "windows") {
        clear_cmd = "cls";
    }
    else {
        clear_cmd = "clear";
    }

    let _ = Command::new(clear_cmd).status();
}

fn invoke(cmd: &str) -> io::Result<Child> {
    if cfg!(target_os = "windows") {
        Command::new("cmd.exe")
                .arg("/C")
                .arg(cmd)
                .spawn()
    }
    else {
        Command::new("sh")
                .arg("-c")
                .arg(cmd)
                .spawn()
    }
}

fn wait(rx: &Receiver<Event>, filter: &NotificationFilter, verbose: bool) -> Result<Event, RecvError> {
    loop {
        // Block on initial notification
        let e = try!(rx.recv());
        if let Some(ref path) = e.path {
            if filter.is_excluded(&path) {
                if verbose {
                    println!("*** Ignoring {} due to filter", path.to_str().unwrap());
                }
                continue;
            }
        }

        // Accumulate subsequent events
        thread::sleep(time::Duration::from_millis(250));

        // Drain rx buffer and drop them
        loop {
            match rx.try_recv() {
                Ok(_) => continue,
                Err(_) => break,
            }
        }

        return Ok(e);
    }
}

fn main() {
    let args = App::new("watchexec")
        .version("0.10.0")
        .about("Execute commands when watched files change")
        .arg(Arg::with_name("path")
            .help("Path to watch")
            .short("w")
            .long("watch")
            .number_of_values(1)
            .multiple(true)
            .takes_value(true)
            .default_value("."))
        .arg(Arg::with_name("command")
            .help("Command to execute")
            .multiple(true)
            .required(true))
        .arg(Arg::with_name("extensions")
             .help("Comma-separated list of file extensions to watch (js,css,html)")
             .short("e")
             .long("exts")
             .takes_value(true))
        .arg(Arg::with_name("clear")
            .help("Clear screen before executing command")
            .short("c")
            .long("clear"))
        .arg(Arg::with_name("restart")
             .help("Restart the process if it's still running")
             .short("r")
             .long("restart"))
        .arg(Arg::with_name("verbose")
             .help("Prints diagnostic messages")
             .short("v")
             .long("verbose"))
        .arg(Arg::with_name("filter")
             .help("Ignore all modifications except those matching the pattern")
             .short("f")
             .long("filter")
             .number_of_values(1)
             .multiple(true)
             .takes_value(true)
             .value_name("pattern"))
        .arg(Arg::with_name("ignore")
             .help("Ignore modifications to paths matching the pattern")
             .short("i")
             .long("ignore")
             .number_of_values(1)
             .multiple(true)
             .takes_value(true)
             .value_name("pattern"))
        .get_matches();

    let verbose = args.is_present("verbose");

    let cwd = env::current_dir().unwrap();
    let mut filter = NotificationFilter::new(&cwd);

    // Add default ignore list
    let dotted_dirs = Path::new(".*").join("*");
    let default_filters = vec!["*.pyc", "*.swp", dotted_dirs.to_str().unwrap()];
    for p in default_filters {
        filter.add_ignore(p).expect("bad default filter");
    }

    if let Some(extensions) = args.values_of("extensions") {
        for ext in extensions {
            filter.add_extension(ext).expect("bad extension");
        }
    }

    if let Some(filters) = args.values_of("filter") {
        for p in filters {
            filter.add_filter(p).expect("bad filter");
        }
    }

    if let Some(ignores) = args.values_of("ignore") {
        for i in ignores {
            filter.add_ignore(i).expect("bad ignore pattern");
        }
    }

    let (tx, rx) = channel();
    let mut watcher: RecommendedWatcher = Watcher::new(tx).expect("unable to create watcher");

    let paths = args.values_of("path").unwrap();
    for path in paths {
        watcher.watch(path).expect("unable to watch path");
    }

    let cmd_parts: Vec<&str> = args.values_of("command").unwrap().collect();
    let cmd = cmd_parts.join(" ");
    let restart = args.is_present("restart");
    let mut child_process: Option<Child> = None;

    loop {
        let e = wait(&rx, &filter, verbose).expect("error when waiting for filesystem changes");

        if let Some(mut child) = child_process {
            if restart {
                let _ = child.kill();
            }

            let _ = child.wait();
        }

        if args.is_present("clear") {
            clear();
        }

        if verbose {
            println!("*** {:?}: {:?}", e.op, e.path);
        }

        if verbose {
            println!("*** Executing: {}", cmd);
        }

        child_process = invoke(&cmd).ok();
    }
}
<|endoftext|>