<commit_before>#![feature(collections_range, range_contains)]

extern crate dotenv;
extern crate itertools;
#[macro_use]
extern crate lazy_static;
extern crate rand;
extern crate serenity;

use std::collections::BTreeMap;
use std::collections::range::RangeArgument;
use std::env;
use std::ops::RangeInclusive;

use dotenv::dotenv;
use itertools::Itertools;
use rand::Rng;
use serenity::prelude::*;
use serenity::model::prelude::*;

trait Command {
    fn required_arg_count(&self) -> RangeInclusive<usize>; //impl RangeArgument<usize>;
    fn exec(&self, ctx: &Context, msg: &Message, args: &[&str]);
}
type CommandMap = BTreeMap<&'static str, Box<Command + Sync>>;

lazy_static! {
    static ref COMMAND_MAP: CommandMap = {
        let mut commands = CommandMap::new();
        commands.insert("help", Box::new(Help));
        commands.insert("flip", Box::new(Flip));
        commands.insert("roll", Box::new(Roll));
        commands
    };
}

fn main() {
    let _ = dotenv();

    let creds = env::var("Z_CREDENTIALS")
        .expect("Unspecified credentials: set Z_CREDENTIALS in the environment (or in `.env`).");
    let mut client = Client::new(&creds, Handler).unwrap();
    client.start().unwrap();
}

struct Handler;
impl EventHandler for Handler {
    fn ready(&self, ctx: Context, _: Ready) {
        ctx.set_presence(Some(Game::playing("Rust")), OnlineStatus::Online)
    }

    fn message(&self, ctx: Context, msg: Message) {
        if msg.content.chars().next() == Some('!') {
            let mut tokens = msg.content[1..].split_whitespace();
            let maybe_command = tokens.next();
            let args = tokens.collect::<Vec<_>>();

            if let Some(command) = maybe_command {
                if let Some(command_handler) = COMMAND_MAP.get(command) {
                    let valid_arg_range = command_handler.required_arg_count();
                    if valid_arg_range.contains(args.len()) {
                        command_handler.exec(&ctx, &msg, &*args);
                    } else {
                        msg.reply(&format!(
                            "This command requires {:?} to {:?} arguments.",
                            valid_arg_range.start(),
                            valid_arg_range.end()
                        )).unwrap();
                    }
                } else {
                    msg.reply(&format!("Unknown command: {}", command)).unwrap();
                }
            } else {
                msg.reply("No command specified.").unwrap();
            }
        }
    }
}

struct Help;
impl Command for Help {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=0
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        let help_output = COMMAND_MAP
            .keys()
            .intersperse(&", !")
            .fold("Available commands:\n!".to_owned(), |output, command| {
                output + command
            });

        msg.channel_id.say(&help_output).unwrap();
    }
}

struct Flip;
impl Command for Flip {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=0
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        if rand::thread_rng().gen() {
            msg.reply("Heads!").unwrap();
        } else {
            msg.reply("Tails!").unwrap();
        }
    }
}

struct Roll;
impl Command for Roll {
    fn required_arg_count(&self) -> RangeInclusive<usize> {
        0..=1
    }

    fn exec(&self, _ctx: &Context, msg: &Message, args: &[&str]) {
        let upper_bound = if args.len() == 0 {
            6
        } else if args.len() == 1 {
            if let Ok(num) = args[0].parse() {
                num
            } else {
                msg.reply("That is not a number.").unwrap();
                return;
            }
        } else {
            unreachable!();
        };

        if upper_bound <= 0 {
            msg.reply("The upper bound must be a positive number.")
                .unwrap();
        } else {
            let result = rand::thread_rng().gen_range(0, upper_bound) + 1;
            msg.reply(&format!("{}", result)).unwrap();
        }
    }
}
<commit_msg>Switch to a ref of the range to avoid copying and be closer to the eventual trait.<commit_after>#![feature(collections_range, range_contains)]

extern crate dotenv;
extern crate itertools;
#[macro_use]
extern crate lazy_static;
extern crate rand;
extern crate serenity;

use std::collections::BTreeMap;
use std::collections::range::RangeArgument;
use std::env;
use std::ops::RangeInclusive;

use dotenv::dotenv;
use itertools::Itertools;
use rand::Rng;
use serenity::prelude::*;
use serenity::model::prelude::*;

trait Command {
    fn required_arg_count(&self) -> &RangeInclusive<usize>; //&RangeArgument<usize>;
    fn exec(&self, ctx: &Context, msg: &Message, args: &[&str]);
}
type CommandMap = BTreeMap<&'static str, Box<Command + Sync>>;

lazy_static! {
    static ref COMMAND_MAP: CommandMap = {
        let mut commands = CommandMap::new();
        commands.insert("help", Box::new(Help));
        commands.insert("flip", Box::new(Flip));
        commands.insert("roll", Box::new(Roll));
        commands
    };
}

fn main() {
    let _ = dotenv();

    let creds = env::var("Z_CREDENTIALS")
        .expect("Unspecified credentials: set Z_CREDENTIALS in the environment (or in `.env`).");
    let mut client = Client::new(&creds, Handler).unwrap();
    client.start().unwrap();
}

struct Handler;
impl EventHandler for Handler {
    fn ready(&self, ctx: Context, _: Ready) {
        ctx.set_presence(Some(Game::playing("Rust")), OnlineStatus::Online)
    }

    fn message(&self, ctx: Context, msg: Message) {
        if msg.content.chars().next() == Some('!') {
            let mut tokens = msg.content[1..].split_whitespace();
            let maybe_command = tokens.next();
            let args = tokens.collect::<Vec<_>>();

            if let Some(command) = maybe_command {
                if let Some(command_handler) = COMMAND_MAP.get(command) {
                    let valid_arg_range = command_handler.required_arg_count();
                    if valid_arg_range.contains(args.len()) {
                        command_handler.exec(&ctx, &msg, &*args);
                    } else {
                        msg.reply(&format!(
                            "This command requires {:?} to {:?} arguments.",
                            valid_arg_range.start(),
                            valid_arg_range.end()
                        )).unwrap();
                    }
                } else {
                    msg.reply(&format!("Unknown command: {}", command)).unwrap();
                }
            } else {
                msg.reply("No command specified.").unwrap();
            }
        }
    }
}

struct Help;
impl Command for Help {
    fn required_arg_count(&self) -> &RangeInclusive<usize> {
        &(0..=0)
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        let help_output = COMMAND_MAP
            .keys()
            .intersperse(&", !")
            .fold("Available commands:\n!".to_owned(), |output, command| {
                output + command
            });

        msg.channel_id.say(&help_output).unwrap();
    }
}

struct Flip;
impl Command for Flip {
    fn required_arg_count(&self) -> &RangeInclusive<usize> {
        &(0..=0)
    }

    fn exec(&self, _ctx: &Context, msg: &Message, _args: &[&str]) {
        if rand::thread_rng().gen() {
            msg.reply("Heads!").unwrap();
        } else {
            msg.reply("Tails!").unwrap();
        }
    }
}

struct Roll;
impl Command for Roll {
    fn required_arg_count(&self) -> &RangeInclusive<usize> {
        &(0..=1)
    }

    fn exec(&self, _ctx: &Context, msg: &Message, args: &[&str]) {
        let upper_bound = if args.len() == 0 {
            6
        } else if args.len() == 1 {
            if let Ok(num) = args[0].parse() {
                num
            } else {
                msg.reply("That is not a number.").unwrap();
                return;
            }
        } else {
            unreachable!();
        };

        if upper_bound <= 0 {
            msg.reply("The upper bound must be a positive number.")
                .unwrap();
        } else {
            let result = rand::thread_rng().gen_range(0, upper_bound) + 1;
            msg.reply(&format!("{}", result)).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate git2;

use git2::{Repository, Commit, Oid, Revwalk, Index};
use std::collections::HashMap;

#[macro_use]
mod macros;

const E_SUCCESS: i32 = 0;
const E_NO_GIT_REPO: i32 = 1;

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

fn real_main() -> i32 {
    let submodule_dir = parse_cli_arguments();
    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;
        }
    };

    let mut submodule_revwalk = get_submodule_revwalk(&repo, &submodule_dir);

    let mut old_id_to_new = HashMap::new();

    rewrite_submodule_history(&repo,
                              &mut submodule_revwalk,
                              &mut old_id_to_new,
                              &submodule_dir);

    let mut repo_revwalk = get_repo_revwalk(&repo);
    rewrite_repo_history(&repo, &mut repo_revwalk, &mut old_id_to_new, &submodule_dir);

    checkout_rewritten_history(&repo, &old_id_to_new);

    E_SUCCESS
}

fn parse_cli_arguments() -> String {
    let options = clap::App::new("git-submerge")
                          .version("0.1")
                          .author("Alexander Batischev <eual.jp@gmail.com>")
                          .about("Merge Git submodule into the main repo \
                                  as if they've never been separate at all")
                          .arg(clap::Arg::with_name("SUBMODULE_DIR")
                               .help("The submodule to merge")
                               .required(true)
                               .index(1))
                          .get_matches();

    // We can safely use unwrap() here because the argument is marked as "required" and Clap checks
    // its presence for us.
    String::from( options.value_of("SUBMODULE_DIR").unwrap() )
}

fn get_submodule_revwalk<'repo>(repo: &'repo Repository, submodule_dir: &str) -> Revwalk<'repo> {
    let submodule_url = String::from("./") + submodule_dir;
    let mut remote = repo.remote_anonymous(&submodule_url).expect("Couldn't create an anonymous remote");
    remote.fetch(&[], None, None).expect("Couldn't fetch submodule's history");
    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");

    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 (#6): 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: &Repository,
                             revwalk: &mut Revwalk,
                             old_id_to_new: &mut HashMap<Oid, Oid>,
                             submodule_dir: &str) {
    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                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));

                // 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 (#11): 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");

                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");

                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 Repository) -> 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 (#6): 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: &Repository,
                        revwalk: &mut Revwalk,
                        old_id_to_new: &mut HashMap<Oid, Oid>,
                        submodule_dir: &str) {
    let submodule_path = std::path::Path::new(submodule_dir);

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                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
                            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");

                // In commits that used to update the submodule, add a parent pointing to
                // appropriate commit in new submodule history
                let mut parent_subtree_ids = std::collections::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
                            {
                                continue;
                            } else {
                                panic!("Error getting submodule's subdir from the tree: {:?}", e);
                            };
                        }
                    }
                }

                // Here's a few pictures to help you understand how we figure out if current commit
                // updated the submodule. If we draw a DAG and name submodule states, the following
                // situations will mean that the submodule wasn't updated:
                //
                //     o--o--o--A--
                //                 `,-A
                //      o--o--o--B-
                //
                // or
                //
                //     o--o--o--A--
                //                 `,-B
                //      o--o--o--B-
                //
                // And in the following graphs the submodule was updated:
                //
                //     o--o--o--A--
                //                 `,-C
                //      o--o--o--B-
                //
                // or
                //
                //     o--o--o--o--A--B
                //
                // Put into words, the rule will be "the submodule state in current commit is
                // different from states in all its parents". Or, more formally, the current state
                // doesn't belong to the set of states in parents.
                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: &Repository, old_id_to_new: &HashMap<Oid, Oid>) {
    let mut checkoutbuilder = git2::build::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");
}
<commit_msg>Drop invalid TODO item<commit_after>extern crate clap;
extern crate git2;

use git2::{Repository, Commit, Oid, Revwalk, Index};
use std::collections::HashMap;

#[macro_use]
mod macros;

const E_SUCCESS: i32 = 0;
const E_NO_GIT_REPO: i32 = 1;

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

fn real_main() -> i32 {
    let submodule_dir = parse_cli_arguments();
    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;
        }
    };

    let mut submodule_revwalk = get_submodule_revwalk(&repo, &submodule_dir);

    let mut old_id_to_new = HashMap::new();

    rewrite_submodule_history(&repo,
                              &mut submodule_revwalk,
                              &mut old_id_to_new,
                              &submodule_dir);

    let mut repo_revwalk = get_repo_revwalk(&repo);
    rewrite_repo_history(&repo, &mut repo_revwalk, &mut old_id_to_new, &submodule_dir);

    checkout_rewritten_history(&repo, &old_id_to_new);

    E_SUCCESS
}

fn parse_cli_arguments() -> String {
    let options = clap::App::new("git-submerge")
                          .version("0.1")
                          .author("Alexander Batischev <eual.jp@gmail.com>")
                          .about("Merge Git submodule into the main repo \
                                  as if they've never been separate at all")
                          .arg(clap::Arg::with_name("SUBMODULE_DIR")
                               .help("The submodule to merge")
                               .required(true)
                               .index(1))
                          .get_matches();

    // We can safely use unwrap() here because the argument is marked as "required" and Clap checks
    // its presence for us.
    String::from( options.value_of("SUBMODULE_DIR").unwrap() )
}

fn get_submodule_revwalk<'repo>(repo: &'repo Repository, submodule_dir: &str) -> Revwalk<'repo> {
    let submodule_url = String::from("./") + submodule_dir;
    let mut remote = repo.remote_anonymous(&submodule_url).expect("Couldn't create an anonymous remote");
    remote.fetch(&[], None, None).expect("Couldn't fetch submodule's history");
    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");

    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 (#6): 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: &Repository,
                             revwalk: &mut Revwalk,
                             old_id_to_new: &mut HashMap<Oid, Oid>,
                             submodule_dir: &str) {
    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                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));

                // 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;

                    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");

                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");

                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 Repository) -> 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 (#6): 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: &Repository,
                        revwalk: &mut Revwalk,
                        old_id_to_new: &mut HashMap<Oid, Oid>,
                        submodule_dir: &str) {
    let submodule_path = std::path::Path::new(submodule_dir);

    for maybe_oid in revwalk {
        match maybe_oid {
            Ok(oid) => {
                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
                            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");

                // In commits that used to update the submodule, add a parent pointing to
                // appropriate commit in new submodule history
                let mut parent_subtree_ids = std::collections::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
                            {
                                continue;
                            } else {
                                panic!("Error getting submodule's subdir from the tree: {:?}", e);
                            };
                        }
                    }
                }

                // Here's a few pictures to help you understand how we figure out if current commit
                // updated the submodule. If we draw a DAG and name submodule states, the following
                // situations will mean that the submodule wasn't updated:
                //
                //     o--o--o--A--
                //                 `,-A
                //      o--o--o--B-
                //
                // or
                //
                //     o--o--o--A--
                //                 `,-B
                //      o--o--o--B-
                //
                // And in the following graphs the submodule was updated:
                //
                //     o--o--o--A--
                //                 `,-C
                //      o--o--o--B-
                //
                // or
                //
                //     o--o--o--o--A--B
                //
                // Put into words, the rule will be "the submodule state in current commit is
                // different from states in all its parents". Or, more formally, the current state
                // doesn't belong to the set of states in parents.
                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: &Repository, old_id_to_new: &HashMap<Oid, Oid>) {
    let mut checkoutbuilder = git2::build::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 rand;
extern crate walkdir;

use walkdir::WalkDir;
use rand::{Rng, thread_rng};
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
use std::io::Error;
use std::cmp;

fn main() {
    let mut recursive: bool = false;
    let mut file: String = String::from("");
    let mut i: i32 = -1;

    for argument in env::args() {
        i += 1;
        if i == 0 {
            continue;
        }

        if argument.to_lowercase() == "--help" || argument.to_lowercase() == "-help" {
            help();
            return;
        } else if argument.to_lowercase() == "--v" || argument.to_lowercase() == "-v" ||
           argument.to_lowercase() == "-version" ||
           argument.to_lowercase() == "--version" {
            version();
            return;
        } else if argument.to_lowercase() == "-r" {
            recursive = true;
        } else {
            file = argument;
            break;
        }
    }
    if file == "" {
        help();
        return;
    }
    file = get_path(&file);

    if recursive {
        for entry in WalkDir::new(file) {
            let entry = entry.unwrap();
            trumpify(entry.path().display().to_string());
        }
    } else {
        trumpify(file)
    }
}

fn get_path2(file: &str) -> Result<String, Error> {
    let path = try!(fs::canonicalize(file));
    Ok(path.display().to_string())
}

fn get_path(file: &str) -> String {
    get_path2(file).unwrap_or(file.to_string())
}

fn read_file2(file: &str) -> Result<String, Error> {
    let mut file = try!(File::open(file));
    let mut contents: Vec<u8> = Vec::new();
    try!(file.read_to_end(&mut contents));
    let ret = String::from_utf8(contents).unwrap_or("".to_string());
    Ok(ret)
}

fn read_file(file: &str) -> String {
    read_file2(file).unwrap_or("".to_string())
}

fn write_file2(file: &str, content: String) -> Result<bool, Error> {
    let mut f = try!(File::create(file));
    try!(f.write_all(content.as_bytes()));

    try!(f.sync_data());
    Ok(false)
}

fn write_file(file: &str, content: String) {
    write_file2(file, content).unwrap_or(false);
}

fn version() {
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump-0.1.0");
    println!("\x1b[32mWebsite:");
    println!("\x1b[0m    https://github.com/x13machine/trump/");
    println!("\x1b[32mCreator:");
    println!("\x1b[0m    <Googolplexking/x13machine> https://googolplex.ninja/");
}
fn help() {
    println!("\x1b[32mHelp:");
    println!("\x1b[0m    trump --help");
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump -v");
    println!("\x1b[32mFiles:");
    println!("\x1b[0m    trump <File>");
    println!("\x1b[32mDirectories:");
    println!("\x1b[0m    trump -r <Directory>");
}

fn trumpify(file: String) {
    let dirs: Vec<&str> = file.split("/").collect::<Vec<&str>>();
    let mut name: String = String::from(dirs[dirs.len() - 1]);
    name = format!("{}{}",
                   &name[0..1].to_uppercase(),
                   &name[1..name.len()].to_lowercase());
    // Ansi Color Codes!!!
    println!("\x1b[32mMaking Great Again:\x1b[0m {}", file);

    let text = format!("Make {} Great Again!", name);

    let mut content: String = read_file(&file);
    if content == "" {
        return;
    }

    let loops = cmp::max(content.len() / text.len() / 2, 1);
    let mut rng = thread_rng();
    for _ in 0..loops {
        let place: usize = rng.gen_range(0, content.len() as u32) as usize;
        let part1: String = String::from(&content[0..place]);
        let part2: String =
            String::from(&content[cmp::min(place + text.len(), content.len())..content.len()]);
        content = format!("{}{}{}", part1, text, part2);
    }
    write_file(&file, content);
}
<commit_msg>to_owned() is faster than to_string()<commit_after>extern crate rand;
extern crate walkdir;

use walkdir::WalkDir;
use rand::{Rng, thread_rng};
use std::env;
use std::fs::File;
use std::fs;
use std::io::prelude::*;
use std::io::Error;
use std::cmp;

fn main() {
    let mut recursive: bool = false;
    let mut file: String = String::from("");
    let mut i: i32 = -1;

    for argument in env::args() {
        i += 1;
        if i == 0 {
            continue;
        }

        if argument.to_lowercase() == "--help" || argument.to_lowercase() == "-help" {
            help();
            return;
        } else if argument.to_lowercase() == "--v" || argument.to_lowercase() == "-v" ||
           argument.to_lowercase() == "-version" ||
           argument.to_lowercase() == "--version" {
            version();
            return;
        } else if argument.to_lowercase() == "-r" {
            recursive = true;
        } else {
            file = argument;
            break;
        }
    }
    if file == "" {
        help();
        return;
    }
    file = get_path(&file);

    if recursive {
        for entry in WalkDir::new(file) {
            let entry = entry.unwrap();
            trumpify(entry.path().display().to_string());
        }
    } else {
        trumpify(file)
    }
}

fn get_path2(file: &str) -> Result<String, Error> {
    let path = try!(fs::canonicalize(file));
    Ok(path.display().to_string())
}

fn get_path(file: &str) -> String {
    get_path2(file).unwrap_or(file.to_owned())
}

fn read_file2(file: &str) -> Result<String, Error> {
    let mut file = try!(File::open(file));
    let mut contents: Vec<u8> = Vec::new();
    try!(file.read_to_end(&mut contents));
    let ret = String::from_utf8(contents).unwrap_or("".to_owned());
    Ok(ret)
}

fn read_file(file: &str) -> String {
    read_file2(file).unwrap_or("".to_owned())
}

fn write_file2(file: &str, content: String) -> Result<bool, Error> {
    let mut f = try!(File::create(file));
    try!(f.write_all(content.as_bytes()));

    try!(f.sync_data());
    Ok(false)
}

fn write_file(file: &str, content: String) {
    write_file2(file, content).unwrap_or(false);
}

fn version() {
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump-0.1.0");
    println!("\x1b[32mWebsite:");
    println!("\x1b[0m    https://github.com/x13machine/trump/");
    println!("\x1b[32mCreator:");
    println!("\x1b[0m    <Googolplexking/x13machine> https://googolplex.ninja/");
}
fn help() {
    println!("\x1b[32mHelp:");
    println!("\x1b[0m    trump --help");
    println!("\x1b[32mVersion:");
    println!("\x1b[0m    trump -v");
    println!("\x1b[32mFiles:");
    println!("\x1b[0m    trump <File>");
    println!("\x1b[32mDirectories:");
    println!("\x1b[0m    trump -r <Directory>");
}

fn trumpify(file: String) {
    let dirs: Vec<&str> = file.split("/").collect::<Vec<&str>>();
    let mut name: String = String::from(dirs[dirs.len() - 1]);
    name = format!("{}{}",
                   &name[0..1].to_uppercase(),
                   &name[1..name.len()].to_lowercase());
    // Ansi Color Codes!!!
    println!("\x1b[32mMaking Great Again:\x1b[0m {}", file);

    let text = format!("Make {} Great Again!", name);

    let mut content: String = read_file(&file);
    if content == "" {
        return;
    }

    let loops = cmp::max(content.len() / text.len() / 2, 1);
    let mut rng = thread_rng();
    for _ in 0..loops {
        let place: usize = rng.gen_range(0, content.len() as u32) as usize;
        let part1: String = String::from(&content[0..place]);
        let part2: String =
            String::from(&content[cmp::min(place + text.len(), content.len())..content.len()]);
        content = format!("{}{}{}", part1, text, part2);
    }
    write_file(&file, content);
}
<|endoftext|>


<commit_before>/*

Copyright 2015 Max Gregor

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

extern crate imagefmt;
extern crate docopt;
extern crate rustc_serialize;

use docopt::Docopt;
use imagefmt::{ColFmt, ColType};

fn main() {

	const USAGE: &'static str = "
Usage:
 rusty_circle <center-x> <center-y> <radius>

Options:
    -h, --help         Show this message.
";

	#[derive(RustcDecodable)]
	struct Args {
		arg_center_x: String,
		arg_center_y: String,
		arg_radius: String,
	}

	// Parse argv and exit the program with an error message if it fails.
	let args: Args = Docopt::new(USAGE)
	.and_then(|d| d.decode())
	.unwrap_or_else(|e| e.exit());

	let radius = args.arg_radius;
	let cx = args.arg_center_x;
	let cy = args.arg_center_y;
	let cxnum: i32;
	let cynum: i32;
	let radiusnum: i32;
	let h = 901;
	let w = 1201;
	let mut image_vector: Vec<u8> = vec![255;(3 * w * h)];
	let w3: i32 = (w * 3) as i32;

	cxnum = match cx.trim().parse(){
						Ok(num) => if num > 0 && num <= 150 {num} else {println!("Please type a y coordinate between 1-150!"); -1},
						Err (_) => {println!("Please type a x coordinate between 1-150!"); return}, };

	radiusnum = match radius.trim().parse(){
						Ok(num) => if num > 0 && num < 100{num} else {println!("Please type a radius between 1-100!"); -1},
						Err (_) => {println!("Please type a number between 1-100!e"); return}, };

	cynum = match cy.trim().parse(){
						Ok(num) => if num > 0 && num <= 200 {num} else {println!("Please type a y coordinate between 1-200!"); -1},
						Err (_) => {println!("Please type a y coordinate between 1-200!"); return}, };

	draw_grid(w3, &mut image_vector);
	draw_circle(cxnum, cynum, radiusnum, w3, &mut image_vector);

	//  write image
	imagefmt::Image{w: w, h: h, fmt:ColFmt::RGB, buf:image_vector}.write("circle.png", ColType::Color).unwrap();

	println!("Circle succussfully saved to circle.png");

}

fn draw_grid(w3: i32, image_vector: &mut Vec<u8>){
	let mut line_counter = 0;
	for i in 0..image_vector.len() {
		if i % (w3 as usize) == 0 {
			for j in 0..201{
				let new_i = (j * 6 * 3) + i;
				image_vector[new_i] = 0;
				image_vector[new_i+1] = 0;
				image_vector[new_i+2] = 0;
			}
			if line_counter == 0{
				for j in 0..w3 as usize{
					image_vector[(j + i) as usize] = 0;
				}
			}

			line_counter += 1;
			if line_counter == 6 {
				line_counter = 0;
			}
		}
	}
}

fn draw_circle(cxnum: i32, cynum: i32, radiusnum: i32, w3: i32, image_vector: &mut Vec<u8>) {
	let mut f: i32 = 1 - radiusnum as i32;
	let mut dd_f_x: i32 = 0;
	let mut dd_f_y: i32 = -2 * radiusnum as i32;
	let mut x: i32 = 0;
	let mut y: i32 = radiusnum;

	// Draw right, left, top and bottom point
	set_point(cxnum, cynum + radiusnum, image_vector, w3);
	set_point(cxnum, cynum - radiusnum, image_vector, w3);
	set_point(cxnum + radiusnum, cynum, image_vector, w3);
	set_point(cxnum - radiusnum, cynum, image_vector, w3);

	while x < y {
		if f >= 0 {
			y -= 1;
			dd_f_y += 2;
			f += dd_f_y;
		}
		x += 1;
		dd_f_x += 2;
		f += dd_f_x + 1;

		set_point(cxnum + x, cynum + y, image_vector, w3);
		set_point(cxnum - x, cynum + y, image_vector, w3);
		set_point(cxnum + x, cynum - y, image_vector, w3);
		set_point(cxnum - x, cynum - y, image_vector, w3);
		set_point(cxnum + y, cynum + x, image_vector, w3);
		set_point(cxnum - y, cynum + x, image_vector, w3);
		set_point(cxnum + y, cynum - x, image_vector, w3);
		set_point(cxnum - y, cynum - x, image_vector, w3);
	}
}

fn set_point(x: i32, y: i32, image_vector: &mut Vec<u8>, w3: i32){
	if x<=200 && y<=150 && x > 0 && y > 0  {
		let x_2d = x * 3 + (x - 1) * 15 - 1;
		let y_2d = y + (y - 1)* 5;
		let offset = y_2d * w3;

		for i in 0..5 {
			for j in 1..16 {
				image_vector[(offset + x_2d + j + (i * w3)) as usize] = 0;
			}
		}
	}
}
<commit_msg>add comments<commit_after>/*

Copyright 2015 Max Gregor

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

extern crate imagefmt;
extern crate docopt;
extern crate rustc_serialize;

use docopt::Docopt;
use imagefmt::{ColFmt, ColType};

/// Main function called on excecution

fn main() {

	// usage string for comandline help
	const USAGE: &'static str = "
Usage:
 rusty_circle <center-x> <center-y> <radius>

Options:
    -h, --help         Show this message.
";

	// Struct for comandline values
	#[derive(RustcDecodable)]
	struct Args {
		arg_center_x: String,
		arg_center_y: String,
		arg_radius: String,
	}

	// Parse argv and exit the program with an error message if it fails.
	let args: Args = Docopt::new(USAGE)
	.and_then(|d| d.decode())
	.unwrap_or_else(|e| e.exit());

	let redius_str = args.arg_radius;
	let cx_str = args.arg_center_x;
	let cy_str = args.arg_center_y;
	// center x coordinate of the circle
	let cx: i32;
	// center y coordinate of the circle
	let cy: i32;
	// center radius of the circle
	let radius: i32;
	// height in pixel of the outputimage
	let h = 901;
	// width in pixel of the outputimage
	let w = 1201;
	// vector for image generation where one pixel is represented by three following entries (Red, Green, Blue).
	let mut image_vector: Vec<u8> = vec![255;(3 * w * h)];
	let w3: i32 = (w * 3) as i32;

	// parse the center x coordinate
	cx = match cx_str.trim().parse(){
						Ok(num) => if num > 0 && num <= 150 {num} else {println!("Please type a y coordinate between 1-150!"); -1},
						Err (_) => {println!("Please type a x coordinate between 1-150!"); return}, };

	// parse the radius
	radius = match redius_str.trim().parse(){
						Ok(num) => if num > 0 && num <= 100{num} else {println!("Please type a radius between 1-100!"); -1},
						Err (_) => {println!("Please type a number between 1-100!e"); return}, };

	// parse the center y coordinate
	cy = match cy_str.trim().parse(){
						Ok(num) => if num > 0 && num <= 200 {num} else {println!("Please type a y coordinate between 1-200!"); -1},
						Err (_) => {println!("Please type a y coordinate between 1-200!"); return}, };

	prepare_grid(w3, &mut image_vector);
	prepare_circle(cx, cy, radius, w3, &mut image_vector);

	//  write image
	imagefmt::Image{w: w, h: h, fmt:ColFmt::RGB, buf:image_vector}.write("circle.png", ColType::Color).unwrap();

	println!("Circle image succussfully saved to circle.png");

}

/// Sets points for a grid in a `Vec<u8>` for image generation where one pixel is represented by three following entries (Red, Green, Blue).
/// Each line of the grid is one pixel wide. The Grid has a widh of 200 points and a heigth of 150 points where one point is 5px x 5px.
/// Additionaly the value for three times the overall width of the output image (`w3`) is needed.

fn prepare_grid(w3: i32, image_vector: &mut Vec<u8>){
	let mut line_counter = 0;
	for i in 0..image_vector.len() {
		if i % (w3 as usize) == 0 {
			for j in 0..201{
				let new_i = (j * 6 * 3) + i;
				image_vector[new_i] = 0;
				image_vector[new_i+1] = 0;
				image_vector[new_i+2] = 0;
			}
			if line_counter == 0{
				for j in 0..w3 as usize{
					image_vector[(j + i) as usize] = 0;
				}
			}

			line_counter += 1;
			if line_counter == 6 {
				line_counter = 0;
			}
		}
	}
}

/// Sets points for a circle with given x (`cx`), y (`cy`) as center coordinates and a radius (`radius`) in a `Vec<u8>` for image generation where
/// one pixel is represented by three following entries (Red, Green, Blue).
/// Additionaly the value for three times the overall width of the output image (`w3`) is needed.

fn prepare_circle(cx: i32, cy: i32, radius: i32, w3: i32, image_vector: &mut Vec<u8>) {
	let mut f: i32 = 1 - radius as i32;
	let mut dd_f_x: i32 = 0;
	let mut dd_f_y: i32 = -2 * radius as i32;
	let mut x: i32 = 0;
	let mut y: i32 = radius;

	// Set right, left, top and bottom point
	set_point(cx, cy + radius, image_vector, w3);
	set_point(cx, cy - radius, image_vector, w3);
	set_point(cx + radius, cy, image_vector, w3);
	set_point(cx - radius, cy, image_vector, w3);

	while x < y {
		if f >= 0 {
			y -= 1;
			dd_f_y += 2;
			f += dd_f_y;
		}
		x += 1;
		dd_f_x += 2;
		f += dd_f_x + 1;

		set_point(cx + x, cy + y, image_vector, w3);
		set_point(cx - x, cy + y, image_vector, w3);
		set_point(cx + x, cy - y, image_vector, w3);
		set_point(cx - x, cy - y, image_vector, w3);
		set_point(cx + y, cy + x, image_vector, w3);
		set_point(cx - y, cy + x, image_vector, w3);
		set_point(cx + y, cy - x, image_vector, w3);
		set_point(cx - y, cy - x, image_vector, w3);
	}
}

/// Sets a point to black (0, 0, 0) with given `x` and `y` coordinates in a `Vec<u8>` for image generation where
/// one pixel is represented by three following entries (Red, Green, Blue).
/// Additionaly the value for three times the overall width of the output image (`w3`) is needed.

fn set_point(x: i32, y: i32, image_vector: &mut Vec<u8>, w3: i32){
	if x<=200 && y<=150 && x > 0 && y > 0  {
		let x_2d = x * 3 + (x - 1) * 15 - 1;
		let y_2d = y + (y - 1)* 5;
		let offset = y_2d * w3;

		for i in 0..5 {
			for j in 1..16 {
				image_vector[(offset + x_2d + j + (i * w3)) as usize] = 0;
			}
		}
	}
}
<|endoftext|>


<commit_before>extern crate turtle;

use std::fmt;
use std::fs::File;
use turtle::{Canvas, Turtle};

trait Alphabet: fmt::Debug + Eq + PartialEq + Clone  {}

#[derive(Clone)]
struct Symbol<C:Alphabet> {
    character: C,
}

struct Parameters;

impl<C:Alphabet> Symbol<C> {
    fn matches(&self, other: &Symbol<C>) -> Option<Parameters> {
        if self.character == other.character {
            // XXX: match condition. XXX move into rule
            Some(Parameters)
        }
        else {
            None
        }
    }
}

impl<C:Alphabet> fmt::Debug for Symbol<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.character)
    }
}

// XXX: Rename SymbolString to Word
#[derive(Clone)]
struct SymbolString<C:Alphabet>(Vec<Symbol<C>>);

impl<C:Alphabet> fmt::Debug for SymbolString<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;
        try!(write!(f, "\""));
        if !v.is_empty() {
            try!(write!(f, "{:?}", v[0]));
            for e in &v[1..] {
                try!(write!(f, " {:?}", e));
            }
        }
        write!(f, "\"")
    }
}

impl<C:Alphabet> SymbolString<C> {
    // XXX: Evaluate Parameters
    fn evaluate(&self, _parameters: Parameters) -> SymbolString<C> {
        self.clone()
    }
}

#[derive(Debug)]
struct Rule<C:Alphabet> {
    lhs: Symbol<C>,
    rhs: SymbolString<C>,
}

impl<C:Alphabet> Rule<C> {
    fn produce(&self, sym: &Symbol<C>) -> Option<SymbolString<C>> {
        self.lhs.matches(sym).map(|parameters| self.rhs.evaluate(parameters))
    }
}

#[derive(Debug)]
struct System<C:Alphabet> {
    rules: Vec<Rule<C>>,
}

impl<C:Alphabet> System<C> {
    fn develop(&self, axiom: SymbolString<C>, iterations: usize) -> (SymbolString<C>, usize) {
        let mut current = axiom;

        for iter in 0..iterations {
            let (next, progress) = self.develop1(&current);
            if !progress {
                return (current, iter);
            }
            current = next;
        }
        return (current, iterations);
    }

    fn develop1(&self, axiom: &SymbolString<C>) -> (SymbolString<C>, bool) {
        let mut expanded = Vec::new();
        let mut any_rule_applied = false;

        for symbol in axiom.0.iter() {
            let mut found = false;
            for rule in self.rules.iter() {
                if let Some(rhs) = rule.produce(&symbol) {
                    expanded.extend(rhs.0);
                    any_rule_applied = true;
                    found = true;
                    break;
                }
            }
            if !found {
                expanded.push(symbol.clone());
            }
        }

        (SymbolString(expanded), any_rule_applied)
    }
}

#[derive(Eq, PartialEq, Clone)]
struct Character(char);
impl Alphabet for Character {}

impl fmt::Debug for Character {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

fn symstr_from_str(s: &str) -> SymbolString<Character> {
    SymbolString(s.chars().filter(|&c| !c.is_whitespace()).map(|c| Symbol{character: Character(c)}).collect())
}

fn sym(c: char) -> Symbol<Character> {
    Symbol { character: Character(c) }
}

fn draw(symstr: &SymbolString<Character>, init_direction: f32, angle: f32, distance: f32, filename: &str) {
    let mut t = Canvas::new();
    t.right(init_direction);
    for sym in symstr.0.iter() {
        match sym.character.0 {
            'F' => t.forward(distance),
            '+' => t.right(angle),
            '-' => t.left(angle),
            '[' => t.push(),
            ']' => t.pop(),
            _   => {}
        }
    }
    t.save_svg(&mut File::create(filename).unwrap()).unwrap();
}

fn koch_curve(maxiter: usize) {
    let axiom = symstr_from_str("F++F++F");

    let system = System { rules: vec![
        Rule {
            lhs: sym('F'),
            rhs: symstr_from_str("F-F++F-F")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, -90.0, 60.0, 10.0, &format!("koch_{:02}.svg", iters));
}

fn dragon_curve(maxiter: usize) {
    let axiom = symstr_from_str("FX");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: symstr_from_str("X+YF+")
        },
        Rule {
            lhs: sym('Y'),
            rhs: symstr_from_str("-FX-Y")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 90.0, 10.0, &format!("dragon_{:02}.svg", iters));
}

fn sierpinski_triangle(maxiter: usize) {
    let axiom = symstr_from_str("A");

    let system = System { rules: vec![
        Rule {
            lhs: sym('A'),
            rhs: symstr_from_str("+B-A-B+")
        },
        Rule {
            lhs: sym('B'),
            rhs: symstr_from_str("-A+B+A-")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    // replace A and B with F
    let system = System { rules: vec![
        Rule {
            lhs: sym('A'),
            rhs: symstr_from_str("F")
        },
        Rule {
            lhs: sym('B'),
            rhs: symstr_from_str("F")
        }
        ] };
    let (after, _iters) = system.develop1(&after);

    draw(&after, -90.0, 60.0, 10.0, &format!("sierpinski_{:02}.svg", iters));
}

fn fractal_plant(maxiter: usize) {
    let axiom = symstr_from_str("X");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: symstr_from_str("F-[[X]+X]+F[+FX]-X")
        },
        Rule {
            lhs: sym('F'),
            rhs: symstr_from_str("FF")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 25.0, 10.0, &format!("plant_{:02}.svg", iters));
}

fn main() {
    for i in 0..7 {
        koch_curve(i);
    }
    for i in 0..16 {
        dragon_curve(i);
    }
    for i in 0..10 {
        sierpinski_triangle(i);
    }
    for i in 4..8 {
        fractal_plant(i);
    }
}
<commit_msg>Rename C:Alphabet to A:Alphabet<commit_after>extern crate turtle;

use std::fmt;
use std::fs::File;
use turtle::{Canvas, Turtle};

trait Alphabet: fmt::Debug + Eq + PartialEq + Clone  {}

#[derive(Clone)]
struct Symbol<A:Alphabet> {
    character: A,
}

struct Parameters;

impl<A:Alphabet> Symbol<A> {
    fn matches(&self, other: &Symbol<A>) -> Option<Parameters> {
        if self.character == other.character {
            // XXX: match condition. XXX move into rule
            Some(Parameters)
        }
        else {
            None
        }
    }
}

impl<A:Alphabet> fmt::Debug for Symbol<A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.character)
    }
}

// XXX: Rename SymbolString to Word
#[derive(Clone)]
struct SymbolString<A:Alphabet>(Vec<Symbol<A>>);

impl<A:Alphabet> fmt::Debug for SymbolString<A> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let v = &self.0;
        try!(write!(f, "\""));
        if !v.is_empty() {
            try!(write!(f, "{:?}", v[0]));
            for e in &v[1..] {
                try!(write!(f, " {:?}", e));
            }
        }
        write!(f, "\"")
    }
}

impl<A:Alphabet> SymbolString<A> {
    // XXX: Evaluate Parameters
    fn evaluate(&self, _parameters: Parameters) -> SymbolString<A> {
        self.clone()
    }
}

#[derive(Debug)]
struct Rule<A:Alphabet> {
    lhs: Symbol<A>,
    rhs: SymbolString<A>,
}

impl<A:Alphabet> Rule<A> {
    fn produce(&self, sym: &Symbol<A>) -> Option<SymbolString<A>> {
        self.lhs.matches(sym).map(|parameters| self.rhs.evaluate(parameters))
    }
}

#[derive(Debug)]
struct System<A:Alphabet> {
    rules: Vec<Rule<A>>,
}

impl<A:Alphabet> System<A> {
    fn develop(&self, axiom: SymbolString<A>, iterations: usize) -> (SymbolString<A>, usize) {
        let mut current = axiom;

        for iter in 0..iterations {
            let (next, progress) = self.develop1(&current);
            if !progress {
                return (current, iter);
            }
            current = next;
        }
        return (current, iterations);
    }

    fn develop1(&self, axiom: &SymbolString<A>) -> (SymbolString<A>, bool) {
        let mut expanded = Vec::new();
        let mut any_rule_applied = false;

        for symbol in axiom.0.iter() {
            let mut found = false;
            for rule in self.rules.iter() {
                if let Some(rhs) = rule.produce(&symbol) {
                    expanded.extend(rhs.0);
                    any_rule_applied = true;
                    found = true;
                    break;
                }
            }
            if !found {
                expanded.push(symbol.clone());
            }
        }

        (SymbolString(expanded), any_rule_applied)
    }
}

#[derive(Eq, PartialEq, Clone)]
struct Character(char);
impl Alphabet for Character {}

impl fmt::Debug for Character {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

fn symstr_from_str(s: &str) -> SymbolString<Character> {
    SymbolString(s.chars().filter(|&c| !c.is_whitespace()).map(|c| Symbol{character: Character(c)}).collect())
}

fn sym(c: char) -> Symbol<Character> {
    Symbol { character: Character(c) }
}

fn draw(symstr: &SymbolString<Character>, init_direction: f32, angle: f32, distance: f32, filename: &str) {
    let mut t = Canvas::new();
    t.right(init_direction);
    for sym in symstr.0.iter() {
        match sym.character.0 {
            'F' => t.forward(distance),
            '+' => t.right(angle),
            '-' => t.left(angle),
            '[' => t.push(),
            ']' => t.pop(),
            _   => {}
        }
    }
    t.save_svg(&mut File::create(filename).unwrap()).unwrap();
}

fn koch_curve(maxiter: usize) {
    let axiom = symstr_from_str("F++F++F");

    let system = System { rules: vec![
        Rule {
            lhs: sym('F'),
            rhs: symstr_from_str("F-F++F-F")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, -90.0, 60.0, 10.0, &format!("koch_{:02}.svg", iters));
}

fn dragon_curve(maxiter: usize) {
    let axiom = symstr_from_str("FX");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: symstr_from_str("X+YF+")
        },
        Rule {
            lhs: sym('Y'),
            rhs: symstr_from_str("-FX-Y")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 90.0, 10.0, &format!("dragon_{:02}.svg", iters));
}

fn sierpinski_triangle(maxiter: usize) {
    let axiom = symstr_from_str("A");

    let system = System { rules: vec![
        Rule {
            lhs: sym('A'),
            rhs: symstr_from_str("+B-A-B+")
        },
        Rule {
            lhs: sym('B'),
            rhs: symstr_from_str("-A+B+A-")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    // replace A and B with F
    let system = System { rules: vec![
        Rule {
            lhs: sym('A'),
            rhs: symstr_from_str("F")
        },
        Rule {
            lhs: sym('B'),
            rhs: symstr_from_str("F")
        }
        ] };
    let (after, _iters) = system.develop1(&after);

    draw(&after, -90.0, 60.0, 10.0, &format!("sierpinski_{:02}.svg", iters));
}

fn fractal_plant(maxiter: usize) {
    let axiom = symstr_from_str("X");

    let system = System { rules: vec![
        Rule {
            lhs: sym('X'),
            rhs: symstr_from_str("F-[[X]+X]+F[+FX]-X")
        },
        Rule {
            lhs: sym('F'),
            rhs: symstr_from_str("FF")
        }
        ] };
    println!("{:?}", system);

    let (after, iters) = system.develop(axiom, maxiter);

    draw(&after, 0.0, 25.0, 10.0, &format!("plant_{:02}.svg", iters));
}

fn main() {
    for i in 0..7 {
        koch_curve(i);
    }
    for i in 0..16 {
        dragon_curve(i);
    }
    for i in 0..10 {
        sierpinski_triangle(i);
    }
    for i in 4..8 {
        fractal_plant(i);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(oak)]

extern crate oak_runtime;
use oak_runtime::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

grammar! awesome {
    #![show_api]

    program
        = (expr / decl / stmt)*

    decl
        = class_decl > to_class_decl
        / method_decl > to_method_decl

    class_decl
        = kw_class spacing ident class_body

    class_body
        = lbracket method_decl* rbracket

    method_decl
        = kw_def spacing ident lparen params_list? rparen block

    block
        = lbracket (stmt / expr)* rbracket

    stmt
        = if_stmt > to_if_stmt
        / while_stmt > to_while_stmt

    if_stmt
        = kw_if expr block (kw_else block)?

    while_stmt
        = kw_while expr block

    assign_expr
        = ident bind_op expr

    expr
        = spacing cond_expr (cond_expr_op cond_expr)* > fold_left

    cond_expr
        = add_expr (add_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (mult_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr

    primary_expr
        = assign_expr > to_assign_expr
        / call > call_expr
        / string > string_expr
        / number > number_expr
        / ident > variable_expr
        / lparen expr rparen

    call
        = (ident ".")? ident lparen arg_list? rparen

    arg_list
        = (expr ("," spacing expr)*)

    params_list
        = (ident ("," spacing ident)*)

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    ident = !digit !keyword ident_char+ spacing > to_string
    ident_char = ["a-zA-Z0-9_"]
    sym_char = ["!@#$%^&*()-=_+[]\\{}|;:,./<>? \n\r\t"]

    digit = ["0-9"]
    number = digit+ spacing > to_number
    string = (dbl_quot_string / sng_quot_string) spacing
    dbl_quot_string = dbl_quot (ident_char / digit / sym_char)* dbl_quot
    sng_quot_string = sng_quot (ident_char / digit / sym_char)* sng_quot
    spacing = [" \n\r\t"]* -> ()

    kw_def = "def"
    kw_class = "class"
    kw_true = "true"
    kw_false = "false"
    kw_nil = "nil"
    kw_if = "if"
    kw_else = "else"
    kw_while = "while"
    kw_tail = !ident_char spacing

    keyword
        = kw_def
        / kw_if
        / kw_else
        / kw_class
        / kw_true
        / kw_false
        / kw_nil
        / kw_tail

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" spacing
    rparen = ")" spacing
    lbracket = spacing "{" spacing
    rbracket = spacing "}" spacing
    dbl_quot = "\""
    sng_quot = "'"

    terminator = (";" / "\n") spacing

    use std::str::FromStr;
    use self::Expression::*;
    use self::BinOp::*;

    pub type PExpr = Box<Expression>;

    #[derive(Debug)]
    pub enum Expression {
        Variable(String),
        NumberLiteral(u32),
        StringLiteral(String),
        BinaryExpr(BinOp, PExpr, PExpr),
        Call(Option<String>, String, Option<(PExpr, Vec<PExpr>)>),
        AssingExpr(String, PExpr),
        MethodDecl(String, Option<(String, Vec<String>)>, Vec<PExpr>),
        ClassDecl(String, Vec<(String, Option<(String, Vec<String>)>, Vec<PExpr>)>),
        IfStatement(PExpr, Vec<PExpr>, Option<Vec<PExpr>>),
        WhileStatement(PExpr, Vec<PExpr>),
        Block(Vec<PExpr>)
    }

    #[derive(Debug)]
    pub enum BinOp {
        Add, Sub, Mul, Div, Lt, Lte, Gt, Gte, Ne, Eq, And, Or
    }

    fn to_number(raw_text: Vec<char>) -> u32 {
        u32::from_str(&*to_string(raw_text)).unwrap()
    }

    fn number_expr(value: u32) -> PExpr {
        Box::new(NumberLiteral(value))
    }

    fn string_expr(raw_text: Vec<char>) -> PExpr {
        Box::new(StringLiteral(to_string(raw_text)))
    }

    fn variable_expr(ident: String) -> PExpr {
        Box::new(Variable(ident))
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn fold_left(head: PExpr, rest: Vec<(BinOp, PExpr)>) -> PExpr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Box::new(BinaryExpr(op, accu, expr)))
    }

    fn fold_right(front: Vec<(PExpr, BinOp)>, last: PExpr) -> PExpr {
        front.into_iter().rev().fold(last,
          |accu, (expr, op)| Box::new(BinaryExpr(op, expr, accu)))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn call_expr(receiver: Option<String>, method: String, args: Option<(PExpr, Vec<PExpr>)>) -> PExpr {
        Box::new(Call(receiver, method, args))
    }

    fn to_assign_expr(variable: String, exp: PExpr) -> PExpr {
        Box::new(AssingExpr(variable, exp))
    }

    fn to_class_decl(name: String, methods: Vec<(String, Option<(String, Vec<String>)>, Vec<PExpr>)>) -> PExpr {
        Box::new(ClassDecl(name, methods))
    }

    fn to_method_decl(name: String, params: Option<(String, Vec<String>)>, body: Vec<PExpr>) -> PExpr {
        Box::new(MethodDecl(name, params, body))
    }

    fn to_if_stmt(condition: PExpr, block: Vec<PExpr>, else_block: Option<Vec<PExpr>>) -> PExpr {
        Box::new(IfStatement(condition, block, else_block))
    }

    fn to_while_stmt(condition: PExpr,  block: Vec<PExpr>) -> PExpr {
      Box::new(WhileStatement(condition, block))
    }
}

fn analyse_state(state: ParseState<StrStream, awesome::PExpr>) {
    match state.into_result() {
        Ok((success, error)) => {
            if success.partial_read() {
                println!("Partial match: {:?} because: {}", success.data, error);
            } else {
                println!("Full match: {:?}", success.data);
            }
        }
        Err(error) => {
            println!("Error: {}", error);
        }
    }
}

fn main() {
    let f = File::open("./src/example.awm").ok().expect("failed to open file");
    let mut reader = BufReader::new(f);
    let mut contents = String::new();
    reader.read_to_string(&mut contents);
    println!("{:?}", awesome::parse_program(contents.stream()));
}
<commit_msg>Reorganized the expression rules.<commit_after>#![feature(plugin)]
#![plugin(oak)]

extern crate oak_runtime;
use oak_runtime::*;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufReader;

grammar! awesome {
    #![show_api]

    program
        = (expr / decl / stmt)*

    decl
        = class_decl > to_class_decl
        / method_decl > to_method_decl

    class_decl
        = kw_class spacing ident class_body

    class_body
        = lbracket method_decl* rbracket

    method_decl
        = kw_def spacing ident lparen params_list? rparen block

    block
        = lbracket (stmt / expr)* rbracket

    stmt
        = if_stmt > to_if_stmt
        / while_stmt > to_while_stmt

    if_stmt
        = kw_if expr block (kw_else block)?

    while_stmt
        = kw_while expr block

    assign_expr
        = ident bind_op expr

    expr = cond_expr

    cond_expr
        = spacing add_expr (cond_expr_op add_expr)* > fold_left

    add_expr
        = mult_expr (add_expr_op mult_expr)* > fold_left

    mult_expr
        = primary_expr (mult_expr_op primary_expr)* > fold_left

    primary_expr
        = assign_expr > to_assign_expr
        / call > call_expr
        / string > string_expr
        / number > number_expr
        / ident > variable_expr
        / lparen expr rparen

    call
        = (ident ".")? ident lparen arg_list? rparen

    arg_list
        = (expr ("," spacing expr)*)

    params_list
        = (ident ("," spacing ident)*)

    add_expr_op
        = add_op > add_bin_op
        / sub_op > sub_bin_op

    mult_expr_op
        = mul_op > mul_bin_op
        / div_op > div_bin_op

    cond_expr_op
        = lt_op > lt_bin_op /
        lte_op > lte_bin_op /
        gt_op > gt_bin_op /
        gte_op > gte_bin_op /
        ne_op > ne_bin_op /
        eq_op > eq_bin_op /
        andand_op > and_bin_op /
        oror_op > or_bin_op

    ident = !digit !keyword ident_char+ spacing > to_string
    ident_char = ["a-zA-Z0-9_"]
    sym_char = ["!@#$%^&*()-=_+[]\\{}|;:,./<>? \n\r\t"]

    digit = ["0-9"]
    number = digit+ spacing > to_number
    string = (dbl_quot_string / sng_quot_string) spacing
    dbl_quot_string = dbl_quot (ident_char / digit / sym_char)* dbl_quot
    sng_quot_string = sng_quot (ident_char / digit / sym_char)* sng_quot
    spacing = [" \n\r\t"]* -> ()

    kw_def = "def"
    kw_class = "class"
    kw_true = "true"
    kw_false = "false"
    kw_nil = "nil"
    kw_if = "if"
    kw_else = "else"
    kw_while = "while"
    kw_tail = !ident_char spacing

    keyword
        = kw_def
        / kw_if
        / kw_else
        / kw_class
        / kw_true
        / kw_false
        / kw_nil
        / kw_tail

    bind_op = "=" spacing
    add_op = "+" spacing
    sub_op = "-" spacing
    mul_op = "*" spacing
    div_op = "/" spacing
    lt_op = "<" spacing
    lte_op = "<=" spacing
    gt_op = ">" spacing
    gte_op = ">=" spacing
    ne_op = "!=" spacing
    eq_op = "==" spacing
    andand_op  = "&&" spacing
    oror_op = "||" spacing

    lparen = "(" spacing
    rparen = ")" spacing
    lbracket = spacing "{" spacing
    rbracket = spacing "}" spacing
    dbl_quot = "\""
    sng_quot = "'"

    terminator = (";" / "\n") spacing

    use std::str::FromStr;
    use self::Expression::*;
    use self::BinOp::*;

    pub type PExpr = Box<Expression>;

    #[derive(Debug)]
    pub enum Expression {
        Variable(String),
        NumberLiteral(u32),
        StringLiteral(String),
        BinaryExpr(BinOp, PExpr, PExpr),
        Call(Option<String>, String, Option<(PExpr, Vec<PExpr>)>),
        AssingExpr(String, PExpr),
        MethodDecl(String, Option<(String, Vec<String>)>, Vec<PExpr>),
        ClassDecl(String, Vec<(String, Option<(String, Vec<String>)>, Vec<PExpr>)>),
        IfStatement(PExpr, Vec<PExpr>, Option<Vec<PExpr>>),
        WhileStatement(PExpr, Vec<PExpr>),
        Block(Vec<PExpr>)
    }

    #[derive(Debug)]
    pub enum BinOp {
        Add, Sub, Mul, Div, Lt, Lte, Gt, Gte, Ne, Eq, And, Or
    }

    fn to_number(raw_text: Vec<char>) -> u32 {
        u32::from_str(&*to_string(raw_text)).unwrap()
    }

    fn number_expr(value: u32) -> PExpr {
        Box::new(NumberLiteral(value))
    }

    fn string_expr(raw_text: Vec<char>) -> PExpr {
        Box::new(StringLiteral(to_string(raw_text)))
    }

    fn variable_expr(ident: String) -> PExpr {
        Box::new(Variable(ident))
    }

    fn to_string(raw_text: Vec<char>) -> String {
        raw_text.into_iter().collect()
    }

    fn fold_left(head: PExpr, rest: Vec<(BinOp, PExpr)>) -> PExpr {
        rest.into_iter().fold(head,
          |accu, (op, expr)| Box::new(BinaryExpr(op, accu, expr)))
    }

    fn fold_right(front: Vec<(PExpr, BinOp)>, last: PExpr) -> PExpr {
        front.into_iter().rev().fold(last,
          |accu, (expr, op)| Box::new(BinaryExpr(op, expr, accu)))
    }

    fn add_bin_op() -> BinOp { Add }
    fn sub_bin_op() -> BinOp { Sub }
    fn mul_bin_op() -> BinOp { Mul }
    fn div_bin_op() -> BinOp { Div }
    fn lt_bin_op() -> BinOp { Lt }
    fn lte_bin_op() -> BinOp { Lte }
    fn gt_bin_op() -> BinOp { Gt }
    fn gte_bin_op() -> BinOp { Gte }
    fn ne_bin_op() -> BinOp { Ne }
    fn eq_bin_op() -> BinOp { Eq }
    fn and_bin_op() -> BinOp { And }
    fn or_bin_op() -> BinOp { Or }

    fn call_expr(receiver: Option<String>, method: String, args: Option<(PExpr, Vec<PExpr>)>) -> PExpr {
        Box::new(Call(receiver, method, args))
    }

    fn to_assign_expr(variable: String, exp: PExpr) -> PExpr {
        Box::new(AssingExpr(variable, exp))
    }

    fn to_class_decl(name: String, methods: Vec<(String, Option<(String, Vec<String>)>, Vec<PExpr>)>) -> PExpr {
        Box::new(ClassDecl(name, methods))
    }

    fn to_method_decl(name: String, params: Option<(String, Vec<String>)>, body: Vec<PExpr>) -> PExpr {
        Box::new(MethodDecl(name, params, body))
    }

    fn to_if_stmt(condition: PExpr, block: Vec<PExpr>, else_block: Option<Vec<PExpr>>) -> PExpr {
        Box::new(IfStatement(condition, block, else_block))
    }

    fn to_while_stmt(condition: PExpr,  block: Vec<PExpr>) -> PExpr {
      Box::new(WhileStatement(condition, block))
    }
}

fn analyse_state(state: ParseState<StrStream, awesome::PExpr>) {
    match state.into_result() {
        Ok((success, error)) => {
            if success.partial_read() {
                println!("Partial match: {:?} because: {}", success.data, error);
            } else {
                println!("Full match: {:?}", success.data);
            }
        }
        Err(error) => {
            println!("Error: {}", error);
        }
    }
}

fn main() {
    let f = File::open("./src/example.awm").ok().expect("failed to open file");
    let mut reader = BufReader::new(f);
    let mut contents = String::new();
    reader.read_to_string(&mut contents);
    println!("{:?}", awesome::parse_program(contents.stream()));
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate staticfile;
extern crate mount;

use std::path::Path;
use std::env;

use iron::Iron;
use staticfile::Static;
use mount::Mount;

fn main() {
	let port = env::args().nth(1).unwrap_or("8080".to_string()).parse::<u16>().unwrap();
	let mut mount = Mount::new();
	mount.mount("/", Static::new(Path::new("./")));
	println!("listening on port {:?}", port);
	Iron::new(mount).http(("127.0.0.1", port)).unwrap();
}
<commit_msg>bind to any ip<commit_after>extern crate iron;
extern crate staticfile;
extern crate mount;

use std::path::Path;
use std::env;

use iron::Iron;
use staticfile::Static;
use mount::Mount;

fn main() {
	let port = env::args().nth(1).unwrap_or("8080".to_string()).parse::<u16>().unwrap();
	let mut mount = Mount::new();
	mount.mount("/", Static::new(Path::new("./")));
	println!("listening on port {:?}", port);
	Iron::new(mount).http(("0.0.0.0", port)).unwrap();
}
<|endoftext|>


<commit_before>#![feature(box_patterns)]

use std::error::Error;
use std::fs::File;

extern crate csv;
use csv::{Reader, StringRecords};

/// The data types supported by this database. Currently just u64 and string but others
/// will be added later, including complex types
#[derive(Debug,Clone)]
enum DataType {
    UnsignedLong,
    String
}

/// Definition of a column in a relation (data set).
#[derive(Debug,Clone)]
struct ColumnMeta {
    name: String,
    data_type: DataType,
    nullable: bool
}

/// Definition of a relation (data set) consisting of one or more columns.
#[derive(Debug,Clone)]
struct TupleType {
    columns: Vec<ColumnMeta>
}

/// Value holder for all supported data types
#[derive(Debug,Clone,PartialEq,PartialOrd)]
enum Value {
    UnsignedLong(u64),
    String(String),
    Boolean(bool)
}

/// A tuple represents one row within a relation and is implemented as a trait to allow for
/// specific implementations for different data sources
trait Tuple {
    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>>;
}

/// A simple tuple implementation for testing and initial prototyping
#[derive(Debug)]
struct SimpleTuple {
    values: Vec<Value>
}

impl Tuple for SimpleTuple {

    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>> {
        Ok(self.values[index].clone())
    }

}

#[derive(Debug)]
enum Operator {
    Eq,
    NotEq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

#[derive(Debug)]
enum Expr {
    /// index into a value within the tuple
    TupleValue(usize),
    /// literal value
    Literal(Value),
    /// binary expression e.g. "age > 21"
    BinaryExpr { left: Box<Expr>, op: Operator, right: Box<Expr> },
}

/// Query plan
#[derive(Debug)]
enum PlanNode {
    TableScan { schema: String, table: String },
    Filter { expr: Expr, input: Box<PlanNode> },
    Project { expr: Vec<Expr>, input: Box<PlanNode> }
}

fn evaluate(tuple: &Tuple, tt: &TupleType, expr: &Expr) -> Result<Value, Box<std::error::Error>> {

    match expr {
        &Expr::BinaryExpr { box ref left, ref op, box ref right } => {
            //TODO: remove use of unwrap() here
            let left_value = evaluate(tuple, tt, left).unwrap();
            let right_value = evaluate(tuple, tt, right).unwrap();
            match op {
                &Operator::Eq => Ok(Value::Boolean(left_value == right_value)),
                &Operator::NotEq => Ok(Value::Boolean(left_value != right_value)),
                &Operator::Lt => Ok(Value::Boolean(left_value < right_value)),
                &Operator::LtEq => Ok(Value::Boolean(left_value <= right_value)),
                &Operator::Gt => Ok(Value::Boolean(left_value > right_value)),
                &Operator::GtEq => Ok(Value::Boolean(left_value >= right_value)),
            }
        },
        &Expr::TupleValue(index) => tuple.get_value(index),
        &Expr::Literal(ref value) => Ok(value.clone()),
    }

}

trait TupleConsumer {
    fn process(&self, tuple: &Tuple);
}

struct DebugConsumer {
}

impl TupleConsumer for DebugConsumer {
    fn process(&self, tuple: &Tuple) {
        //println!("Tuple: {:?}", tuple);
    }
}

struct FilterConsumer {
    tuple_type: TupleType,
    filter_expr: Expr
}

impl TupleConsumer for FilterConsumer {
    fn process(&self, tuple: &Tuple) {
        let x = evaluate(tuple, &self.tuple_type, &self.filter_expr);
        println!("Filter expr evaluates to {:?}", x);
//        match  {
//            Ok(v) => {
//                match v {
//                    Value::
//                }
//
//            },
//            Err(e) => {
//
//            }
//
//        }

    }
}

trait Relation {
    fn next(&self) -> Result<Option<Box<Tuple>>, Box<Error>>;
}

struct CsvRelation {
    filename: String,
    tuple_type: TupleType,
    reader: csv::Reader<File>,
    //records: Option<csv::StringRecords<'a, File>>
}

impl CsvRelation {

    fn open(filename: String, tuple_type: TupleType) -> Self {
        let mut rdr = csv::Reader::from_file(&filename).unwrap();
        CsvRelation {
            filename: filename,
            tuple_type: tuple_type,
            reader: rdr,
      //      records: None,
        }
    }

//    fn init(&self) {
//        self.records = Some(self.reader.records());
//    }

    fn scan(&mut self, consumer: &TupleConsumer) {
        // iterate over data
        let mut records = self.reader.records();
        while let Some(row) = records.next() {
            let data : Vec<String> = row.unwrap();

            // for now, do an expensive translation of strings to the specific tuple type for
            // every single column
            let mut converted : Vec<Value> = vec![];
            for i in 0..data.len() {
                converted.push(match self.tuple_type.columns[i].data_type {
                    DataType::UnsignedLong => Value::UnsignedLong(data[i].parse::<u64>().unwrap()),
                    DataType::String => Value::String(data[i].clone()),
                });
            }
            let tuple = SimpleTuple { values: converted };

            consumer.process(&tuple);

        }

    }

}

//impl Relation for CsvRelation {

//    fn next(&self) -> Result<Option<Box<Tuple>>, Box<Error>> {
//        match self.records.next() {
//            Ok(Some(row)) => {
//                let data: Vec<String> = row.unwrap();
//                println!("Row: {:?}", data);
//
//                // for now, do an expensive translation of strings to the specific tuple type for
//                // every single column
//                let mut converted: Vec<Value> = vec![];
//                for i in 0..data.len() {
//                    converted.push(match self.tuple_type.columns[i].data_type {
//                        DataType::UnsignedLong => Value::UnsignedLong(data[i].parse::<u64>().unwrap()),
//                        DataType::String => Value::String(data[i].clone()),
//                    });
//                }
//                Ok(Some(Box::new(SimpleTuple { values: converted })));
//            },
//            Ok(None) => Ok(None),
//            Err(e) => Err(e)
//        }
//        Ok(None)
//    }
//}

//fn execute(node: &PlanNode) {
//    match node {
//        &PlanNode::TableScan { schema, table } => {
//
//        },
//        &PlanNode::Filter { expr, input } => {
//
//        },
//        &PlanNode::Project { expr, input } => {
//
//        }
//    }
//}

fn main() {

    // define schema for data source (csv file)
    let tt = TupleType {
        columns: vec![
            ColumnMeta { name: String::from("id"), data_type: DataType::UnsignedLong, nullable: false },
            ColumnMeta { name: String::from("name"), data_type: DataType::String, nullable: false }
        ]
    };

    // create simple filter expression for "id = 2"
    let filter_expr = Expr::BinaryExpr {
        left: Box::new(Expr::TupleValue(0)),
        op: Operator::Eq,
        right: Box::new(Expr::Literal(Value::UnsignedLong(2)))
    };

//    let consumer = DebugConsumer {};

    let filter_consumer = FilterConsumer { tuple_type: tt.clone(), filter_expr: filter_expr };

    let mut csv = CsvRelation::open(String::from("people.csv"), tt);
    csv.scan(&filter_consumer);

    // execute scan with filter expr against csv file
//    let mut rdr = csv::Reader::from_file("people.csv").unwrap();
//    let mut records = rdr.records();
//
//    // iterate over data
//    while let Some(row) = records.next() {
//        let data : Vec<String> = row.unwrap();
//        println!("Row: {:?}", data);
//
//        // for now, do an expensive translation of strings to the specific tuple type for
//        // every single column
//        let mut converted : Vec<Value> = vec![];
//        for i in 0..data.len() {
//            converted.push(match tt.columns[i].data_type {
//                    DataType::UnsignedLong => Value::UnsignedLong(data[i].parse::<u64>().unwrap()),
//                    DataType::String => Value::String(data[i].clone()),
//            });
//        }
//        let tuple = SimpleTuple { values: converted };
//
//        let is_match = evaluate(&tuple, &tt, &filter_expr).unwrap();
//        println!("filter expr evaluates to {:?}", is_match);
//    }
//
}
<commit_msg>code cleanup<commit_after>#![feature(box_patterns)]

use std::error::Error;
use std::fs::File;

extern crate csv;
use csv::{Reader, StringRecords};

/// The data types supported by this database. Currently just u64 and string but others
/// will be added later, including complex types
#[derive(Debug,Clone)]
enum DataType {
    UnsignedLong,
    String
}

/// Definition of a column in a relation (data set).
#[derive(Debug,Clone)]
struct ColumnMeta {
    name: String,
    data_type: DataType,
    nullable: bool
}

/// Definition of a relation (data set) consisting of one or more columns.
#[derive(Debug,Clone)]
struct TupleType {
    columns: Vec<ColumnMeta>
}

/// Value holder for all supported data types
#[derive(Debug,Clone,PartialEq,PartialOrd)]
enum Value {
    UnsignedLong(u64),
    String(String),
    Boolean(bool)
}

/// A tuple represents one row within a relation and is implemented as a trait to allow for
/// specific implementations for different data sources
trait Tuple {
    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>>;
}

/// A simple tuple implementation for testing and initial prototyping
#[derive(Debug)]
struct SimpleTuple {
    values: Vec<Value>
}

impl Tuple for SimpleTuple {

    fn get_value(&self, index: usize) -> Result<Value, Box<std::error::Error>> {
        Ok(self.values[index].clone())
    }

}

#[derive(Debug)]
enum Operator {
    Eq,
    NotEq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

#[derive(Debug)]
enum Expr {
    /// index into a value within the tuple
    TupleValue(usize),
    /// literal value
    Literal(Value),
    /// binary expression e.g. "age > 21"
    BinaryExpr { left: Box<Expr>, op: Operator, right: Box<Expr> },
}

/// Query plan
#[derive(Debug)]
enum PlanNode {
    TableScan { schema: String, table: String },
    Filter { expr: Expr, input: Box<PlanNode> },
    Project { expr: Vec<Expr>, input: Box<PlanNode> }
}

fn evaluate(tuple: &Tuple, tt: &TupleType, expr: &Expr) -> Result<Value, Box<std::error::Error>> {

    match expr {
        &Expr::BinaryExpr { box ref left, ref op, box ref right } => {
            //TODO: remove use of unwrap() here
            let left_value = evaluate(tuple, tt, left).unwrap();
            let right_value = evaluate(tuple, tt, right).unwrap();
            match op {
                &Operator::Eq => Ok(Value::Boolean(left_value == right_value)),
                &Operator::NotEq => Ok(Value::Boolean(left_value != right_value)),
                &Operator::Lt => Ok(Value::Boolean(left_value < right_value)),
                &Operator::LtEq => Ok(Value::Boolean(left_value <= right_value)),
                &Operator::Gt => Ok(Value::Boolean(left_value > right_value)),
                &Operator::GtEq => Ok(Value::Boolean(left_value >= right_value)),
            }
        },
        &Expr::TupleValue(index) => tuple.get_value(index),
        &Expr::Literal(ref value) => Ok(value.clone()),
    }

}

trait TupleConsumer {
    fn process(&self, tuple: &Tuple);
}

struct DebugConsumer {
}

impl TupleConsumer for DebugConsumer {
    fn process(&self, tuple: &Tuple) {
        //println!("Tuple: {:?}", tuple);
    }
}

struct FilterConsumer {
    tuple_type: TupleType,
    filter_expr: Expr
}

impl TupleConsumer for FilterConsumer {
    fn process(&self, tuple: &Tuple) {
        let x = evaluate(tuple, &self.tuple_type, &self.filter_expr);
        println!("Filter expr evaluates to {:?}", x);
    }
}

trait Relation {
    fn scan(&mut self, &TupleConsumer);
}

struct CsvRelation {
    filename: String,
    tuple_type: TupleType,
    reader: csv::Reader<File>,
    //records: Option<csv::StringRecords<'a, File>>
}

impl CsvRelation {
    fn open(filename: String, tuple_type: TupleType) -> Self {
        let mut rdr = csv::Reader::from_file(&filename).unwrap();
        CsvRelation {
            filename: filename,
            tuple_type: tuple_type,
            reader: rdr,
            //      records: None,
        }
    }

    //    fn init(&self) {
    //        self.records = Some(self.reader.records());
    //    }
}

impl Relation for CsvRelation {

    fn scan(&mut self, consumer: &TupleConsumer) {
        // iterate over data
        let mut records = self.reader.records();
        while let Some(row) = records.next() {
            let data : Vec<String> = row.unwrap();

            // for now, do an expensive translation of strings to the specific tuple type for
            // every single column
            let mut converted : Vec<Value> = vec![];
            for i in 0..data.len() {
                converted.push(match self.tuple_type.columns[i].data_type {
                    DataType::UnsignedLong => Value::UnsignedLong(data[i].parse::<u64>().unwrap()),
                    DataType::String => Value::String(data[i].clone()),
                });
            }
            let tuple = SimpleTuple { values: converted };

            consumer.process(&tuple);

        }

    }

}

fn main() {

    // define schema for data source (csv file)
    let tt = TupleType {
        columns: vec![
            ColumnMeta { name: String::from("id"), data_type: DataType::UnsignedLong, nullable: false },
            ColumnMeta { name: String::from("name"), data_type: DataType::String, nullable: false }
        ]
    };

    // open csv file
    let mut csv = CsvRelation::open(String::from("people.csv"), tt.clone());

    // create simple filter expression for "id = 2"
    let filter_expr = Expr::BinaryExpr {
        left: Box::new(Expr::TupleValue(0)),
        op: Operator::Eq,
        right: Box::new(Expr::Literal(Value::UnsignedLong(2)))
    };

    let filter_consumer = FilterConsumer { tuple_type: tt.clone(), filter_expr: filter_expr };

    csv.scan(&filter_consumer);
}
<|endoftext|>