<commit_before>#![feature(plugin)]

extern crate csv;

#[plugin] #[no_link]
extern crate regex_macros;
extern crate regex;

extern crate "rustc-serialize" as rustc_serialize;

use std::io::{File, BufferedReader};
use std::option::{Option};
use std::str::{FromStr};

#[derive(RustcEncodable)]
struct User {
    id: Option<i32>,
    email: Option<String>,
    created_at: Option<String>,
    details: Option<String>,
    external_id: Option<i32>,
    is_active: Option<bool>,
    last_login: Option<String>,
    name: Option<String>,
    notes: Option<String>,
    organization_id: Option<i32>,
    phone: Option<String>,
    updated_at: Option<String>,
    is_verified: Option<bool>
}

impl User {
    fn empty() -> User {
        User {
            id: None,
            email: None,
            created_at: None,
            details: None,
            external_id: None,
            is_active: None,
            last_login: None,
            name: None,
            notes: None,
            organization_id: None,
            phone: None,
            updated_at: None,
            is_verified: None,
        }
    }
}

fn main() {
    let mut xml_reader = BufferedReader::new(File::open(&Path::new("xml-data/users.xml")));
    let mut csv_writer = csv::Writer::from_file(&Path::new("users.csv"));

    let _ = csv_writer.encode(("id", "email", "created-at", "details", "external-id", "is-active", "last-login", "name",
        "organization-id", "phone", "updated-at", "is-verified"));

    let re_begin_user = regex!(r"<user>");
    let re_end_user = regex!(r"</user>");
    let re_id = regex!(r"<id.*?>(.*)</id>");
    let re_email = regex!(r"<email.*?>(.*)</email>");
    let re_created_at = regex!(r"<created-at.*?>(.*)</created-at>");
    let re_details = regex!(r"(.*)");
    let re_external_id = regex!(r"<external-id.*?>(.*)</external-id>");
    let re_is_active = regex!(r"<is-active.*?>(.*)</is-active>");
    let re_last_login = regex!(r"<last-login.*?>(.*)</last-login>");
    let re_organization_id = regex!(r"<organization-id.*?>(.*)</organization-id>");
    let re_phone = regex!(r"<phone.*?>(.*)</phone>");
    let re_updated_at = regex!(r"<updated-at.*?>(.*)</updated-at>");
    let re_is_verified = regex!(r"<is-verified.*?>(.*)</is-verified>");

    let mut user = User::empty();

    for l in xml_reader.lines() {
        let a: String = l.unwrap();
        let line: &str = a.as_slice();

        if re_begin_user.is_match(line) {
            user = User::empty();
        } else if re_end_user.is_match(line) {
            csv_writer.encode(&user);
        } else if re_id.is_match(line) {
            user.id = first_capture_as_i32(re_id.captures(line));
        } else if re_email.is_match(line) {
            user.email = first_capture_as_string(re_email.captures(line));
        } else if re_created_at.is_match(line) {
            user.created_at = first_capture_as_string(re_created_at.captures(line));
        } else if re_details.is_match(line) {
            user.details = first_capture_as_string(re_details.captures(line));
        } else if re_external_id.is_match(line) {
            user.external_id = first_capture_as_i32(re_external_id.captures(line));
        } else if re_is_active.is_match(line) {
            user.is_active = first_capture_as_bool(re_is_active.captures(line));
        } else if re_last_login.is_match(line) {
            user.last_login = first_capture_as_string(re_last_login.captures(line));
        } else if re_organization_id.is_match(line) {
            user.organization_id = first_capture_as_i32(re_organization_id.captures(line));
        } else if re_phone.is_match(line) {
            user.phone = first_capture_as_string(re_phone.captures(line));
        } else if re_updated_at.is_match(line) {
            user.updated_at = first_capture_as_string(re_updated_at.captures(line));
        } else if re_is_verified.is_match(line) {
            user.is_verified = first_capture_as_bool(re_is_verified.captures(line));
        }
    }
    let _ = csv_writer.flush();
}

fn first_capture_as_string(caps_line: Option<regex::Captures>) -> Option<String> {
    match caps_line {
        Some(caps) => { caps.at(1).map(|cap| cap.to_string()) },
        None => { None }
    }
}

fn first_capture_as_i32(caps_line: Option<regex::Captures>) -> Option<i32> {
    match caps_line {
        Some(caps) => { caps.at(1).and_then(|cap| FromStr::from_str(cap)) },
        None => { None }
    }
}

fn first_capture_as_bool(caps_line: Option<regex::Captures>) -> Option<bool> {
    match caps_line {
        Some(caps) => { caps.at(1).map(|cap| cap == "true") },
        None => { None }
    }
}
<commit_msg>factor our user code to function<commit_after>#![feature(plugin)]

extern crate csv;

#[plugin] #[no_link]
extern crate regex_macros;
extern crate regex;

extern crate "rustc-serialize" as rustc_serialize;

use std::io::{File, BufferedReader};
use std::option::{Option};
use std::str::{FromStr};

#[derive(RustcEncodable)]
struct User {
    id: Option<i32>,
    email: Option<String>,
    created_at: Option<String>,
    details: Option<String>,
    external_id: Option<i32>,
    is_active: Option<bool>,
    last_login: Option<String>,
    name: Option<String>,
    notes: Option<String>,
    organization_id: Option<i32>,
    phone: Option<String>,
    updated_at: Option<String>,
    is_verified: Option<bool>
}

impl User {
    fn empty() -> User {
        User {
            id: None,
            email: None,
            created_at: None,
            details: None,
            external_id: None,
            is_active: None,
            last_login: None,
            name: None,
            notes: None,
            organization_id: None,
            phone: None,
            updated_at: None,
            is_verified: None,
        }
    }
}

fn main() {
    handle_users();
}

fn handle_users() {
    let mut xml_reader = BufferedReader::new(File::open(&Path::new("xml-data/users.xml")));
    let mut csv_writer = csv::Writer::from_file(&Path::new("users.csv"));

    let _ = csv_writer.encode(("id", "email", "created-at", "details", "external-id", "is-active", "last-login", "name",
        "organization-id", "phone", "updated-at", "is-verified"));

    let re_begin_user = regex!(r"<user>");
    let re_end_user = regex!(r"</user>");
    let re_id = regex!(r"<id.*?>(.*)</id>");
    let re_email = regex!(r"<email.*?>(.*)</email>");
    let re_created_at = regex!(r"<created-at.*?>(.*)</created-at>");
    let re_details = regex!(r"(.*)");
    let re_external_id = regex!(r"<external-id.*?>(.*)</external-id>");
    let re_is_active = regex!(r"<is-active.*?>(.*)</is-active>");
    let re_last_login = regex!(r"<last-login.*?>(.*)</last-login>");
    let re_organization_id = regex!(r"<organization-id.*?>(.*)</organization-id>");
    let re_phone = regex!(r"<phone.*?>(.*)</phone>");
    let re_updated_at = regex!(r"<updated-at.*?>(.*)</updated-at>");
    let re_is_verified = regex!(r"<is-verified.*?>(.*)</is-verified>");

    let mut user = User::empty();

    for l in xml_reader.lines() {
        let a: String = l.unwrap();
        let line: &str = a.as_slice();

        if re_begin_user.is_match(line) {
            user = User::empty();
        } else if re_end_user.is_match(line) {
            csv_writer.encode(&user);
        } else if re_id.is_match(line) {
            user.id = first_capture_as_i32(re_id.captures(line));
        } else if re_email.is_match(line) {
            user.email = first_capture_as_string(re_email.captures(line));
        } else if re_created_at.is_match(line) {
            user.created_at = first_capture_as_string(re_created_at.captures(line));
        } else if re_details.is_match(line) {
            user.details = first_capture_as_string(re_details.captures(line));
        } else if re_external_id.is_match(line) {
            user.external_id = first_capture_as_i32(re_external_id.captures(line));
        } else if re_is_active.is_match(line) {
            user.is_active = first_capture_as_bool(re_is_active.captures(line));
        } else if re_last_login.is_match(line) {
            user.last_login = first_capture_as_string(re_last_login.captures(line));
        } else if re_organization_id.is_match(line) {
            user.organization_id = first_capture_as_i32(re_organization_id.captures(line));
        } else if re_phone.is_match(line) {
            user.phone = first_capture_as_string(re_phone.captures(line));
        } else if re_updated_at.is_match(line) {
            user.updated_at = first_capture_as_string(re_updated_at.captures(line));
        } else if re_is_verified.is_match(line) {
            user.is_verified = first_capture_as_bool(re_is_verified.captures(line));
        }
    }
    let _ = csv_writer.flush();
}

fn first_capture_as_string(caps_line: Option<regex::Captures>) -> Option<String> {
    match caps_line {
        Some(caps) => { caps.at(1).map(|cap| cap.to_string()) },
        None => { None }
    }
}

fn first_capture_as_i32(caps_line: Option<regex::Captures>) -> Option<i32> {
    match caps_line {
        Some(caps) => { caps.at(1).and_then(|cap| FromStr::from_str(cap)) },
        None => { None }
    }
}

fn first_capture_as_bool(caps_line: Option<regex::Captures>) -> Option<bool> {
    match caps_line {
        Some(caps) => { caps.at(1).map(|cap| cap == "true") },
        None => { None }
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate gsdmm;

use gsdmm::GSDMM;
use docopt::Docopt;
use std::io::{BufRead,BufReader};
use std::fs::File;
use std::collections::HashSet;
use std::io::Write;

const USAGE: &'static str ="
Gibbs sampling algorithm for a Dirichlet Mixture Model of Yin and Wang 2014.

Usage:
  gsdmm <datafile> <vocabfile> <outprefix> [-k <max_clusters>] [-a <alpha>] [-b <beta>] [-m <maxit>]
  gsdmm (-h | --help)
  gsdmm --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  -k=<K>                Upper bound on the number of possible clusters. [default: 8]
  -a --alpha=<alpha>    Alpha controls the probability that a student will join a table that is currently empty
                        When alpha is 0, no one will join an empty table. [default: 0.1]
  -b --beta=<beta>      Beta controls the student's affinity for other students with similar interests. A low beta means
                        that students desire to sit with students of similar interests. A high beta means they are less
                        concerned with affinity and are more influenced by the popularity of a table. [default: 0.1]
  -m --maxit=<m>        Maximum number of iterations. [default: 30]

";

#[derive(Debug, RustcDecodable)]
struct Args {
    //    flag_mode: isize,
    arg_datafile: String,
    arg_vocabfile: String,
    arg_outprefix: String,
    flag_k: usize,
    flag_alpha: f64,
    flag_beta: f64,
    flag_maxit: isize
}

fn main() {

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    // get the data and vocabulary
    let vocab:HashSet<String> = lines_from_file(&args.arg_vocabfile).into_iter().collect();
    let docs:Vec<Vec<String>> = lines_from_file(&args.arg_datafile).into_iter().map(|line| {
        let mut term_vector = line.to_owned()
            .split_whitespace()
            .map(|s| s.to_owned())
            .filter(|s| (&vocab).contains(s))
            .collect::<Vec<String>>();

        // sort and dedupe: this implementation requires binary term counts
        term_vector.sort();
        term_vector.dedup();
        term_vector
    }).collect::<Vec<Vec<String>>>();

    let mut model = GSDMM::new(args.flag_alpha, args.flag_beta, args.flag_k, args.flag_maxit, vocab, docs);
    model.fit();

    // write the labels
    {
        let fname = (&args.arg_outprefix).clone() + "labels.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        let mut scored = Vec::<(String,String,String)>::new();
        for doc in & (model.docs) {
            let p = model.score( & doc);
            let mut row = p.iter().enumerate().collect::<Vec<_>>();
            row.sort_by(|a,b| a.1.partial_cmp(b.1).unwrap());
            let line = row.pop().unwrap();
            scored.push((line.0.to_string(), line.1.to_string(), doc.join(" ")));
        }
        scored.sort();
        for (label, score, txt) in scored {
            f.write((label + "," + &score + "," + &txt + "\n").as_bytes());
        }
    }

    // write the label probabilities
    {
        let fname = (&args.arg_outprefix).clone() + "label_probabilities.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        for doc in & (model.docs) {
            let p = model.score( & doc);
            let line = p.iter().map( | k | (*k as f32).to_string()).collect::< Vec< String > > ().join(",");
            f.write((line + "\n").as_bytes());
        }
    }

    // write the cluster descriptions
    {
        let fname = (&args.arg_outprefix).clone() + "cluster_descriptions.txt";
        let error_msg = format!("Could not write file {}!", fname);
        let mut f = File::create(fname).expect(&error_msg);
        for k in 0..args.flag_k {
            let ref word_dist = model.cluster_word_distributions[k];
            let mut line = k.to_string() + " ";
            let mut dist_counts:Vec<String> = word_dist.iter().map(|(a,b)| a.clone() + ":" + &b.clone().to_string() ).collect();
            dist_counts.sort();
            line += &dist_counts.join(" ");
            f.write((line+"\n").as_bytes());
        }
    }

    fn lines_from_file(filename: &str) -> Vec<String>
    {
        let error_msg = format!("Could not read file {}!", filename);
        let file = File::open(filename).expect(&error_msg);
        let buf = BufReader::new(file);
        buf.lines().map(|l| l.expect("Could not parse line!")).collect()
    }
}
<commit_msg>Improve the output in the runner<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate gsdmm;

use gsdmm::GSDMM;
use docopt::Docopt;
use std::io::{BufRead,BufReader};
use std::fs::File;
use std::collections::HashSet;
use std::io::Write;

const USAGE: &'static str ="
Gibbs sampling algorithm for a Dirichlet Mixture Model of Yin and Wang 2014.

Usage:
  gsdmm <datafile> <vocabfile> <outprefix> [-k <max_clusters>] [-a <alpha>] [-b <beta>] [-m <maxit>]
  gsdmm (-h | --help)
  gsdmm --version

Options:
  -h --help             Show this screen.
  --version             Show version.
  -k=<K>                Upper bound on the number of possible clusters. [default: 8]
  -a --alpha=<alpha>    Alpha controls the probability that a student will join a table that is currently empty
                        When alpha is 0, no one will join an empty table. [default: 0.1]
  -b --beta=<beta>      Beta controls the student's affinity for other students with similar interests. A low beta means
                        that students desire to sit with students of similar interests. A high beta means they are less
                        concerned with affinity and are more influenced by the popularity of a table. [default: 0.1]
  -m --maxit=<m>        Maximum number of iterations. [default: 30]

";

#[derive(Debug, RustcDecodable)]
struct Args {
    //    flag_mode: isize,
    arg_datafile: String,
    arg_vocabfile: String,
    arg_outprefix: String,
    flag_k: usize,
    flag_alpha: f64,
    flag_beta: f64,
    flag_maxit: isize
}

fn main() {

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    // get the data and vocabulary
    let vocab:HashSet<String> = lines_from_file(&args.arg_vocabfile).into_iter().collect();
    let docs:Vec<Vec<String>> = lines_from_file(&args.arg_datafile).into_iter().map(|line| {
        let mut term_vector = line.to_owned()
            .split_whitespace()
            .map(|s| s.to_owned())
            .filter(|s| (&vocab).contains(s))
            .collect::<Vec<String>>();

        // sort and dedupe: this implementation requires binary term counts
        term_vector.sort();
        term_vector.dedup();
        term_vector
    }).collect::<Vec<Vec<String>>>();

    let mut model = GSDMM::new(args.flag_alpha, args.flag_beta, args.flag_k, args.flag_maxit, vocab, docs);
    model.fit();

    // write the labels
    {
        let fname = (&args.arg_outprefix).clone() + "labels.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        let mut scored = Vec::<(String,String,String)>::new();

        // zip with the input data so we get clustered, raw input documents in the output set
        for (doc,txt) in (&model.docs).iter().zip(lines_from_file(&args.arg_datafile).iter()) {
            let p = model.score( & doc);
            let mut row = p.iter().enumerate().collect::<Vec<_>>();
            row.sort_by(|a,b| a.1.partial_cmp(b.1).unwrap());
            let line = row.pop().unwrap();
            scored.push((line.0.to_string(), line.1.to_string(), txt.clone()));
        }
        scored.sort();
        for (label, score, txt) in scored {
            f.write((label + "," + &score + "," + &txt + "\n").as_bytes());
        }
    }

    // write the label probabilities
    {
        let fname = (&args.arg_outprefix).clone() + "label_probabilities.csv";
        let error_msg = format ! ("Could not write file {}!", fname);
        let mut f = File::create( fname ).expect( & error_msg);
        for doc in & (model.docs) {
            let p = model.score( & doc);
            let line = p.iter().map( | k | (*k as f32).to_string()).collect::< Vec< String > > ().join(",");
            f.write((line + "\n").as_bytes());
        }
    }

    // write the cluster descriptions
    {
        let fname = (&args.arg_outprefix).clone() + "cluster_descriptions.txt";
        let error_msg = format!("Could not write file {}!", fname);
        let mut f = File::create(fname).expect(&error_msg);
        for k in 0..args.flag_k {
            let ref word_dist = model.cluster_word_distributions[k];
            let mut line = k.to_string() + " ";
            let mut dist_counts:Vec<String> = word_dist.iter().map(|(a,b)| a.clone() + ":" + &b.clone().to_string() ).collect();
            dist_counts.sort();
            line += &dist_counts.join(" ");
            f.write((line+"\n").as_bytes());
        }
    }

    fn lines_from_file(filename: &str) -> Vec<String>
    {
        let error_msg = format!("Could not read file {}!", filename);
        let file = File::open(filename).expect(&error_msg);
        let buf = BufReader::new(file);
        buf.lines().map(|l| l.expect("Could not parse line!")).collect()
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#[macro_use]
extern crate clap;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::env;
use std::io::prelude::*;
use std::fs::File;
use clap::App;

mod github;

static GITHUB_TOKEN: &'static str = "RP_GITHUBTOKEN";

fn main() {
    let yaml = load_yaml!("release-party.yml");
    let matches = App::from_yaml(yaml).get_matches();

    let org_url = make_org_url(&matches);
    let token = get_github_token();
    let reqwest_client = get_reqwest_client();

    print_party_links(get_pr_links(
        &get_repos_we_care_about(&token, &org_url, &reqwest_client),
        &token,
        &reqwest_client,
        is_dryrun(&matches),
    ));
}

fn is_dryrun(matches: &clap::ArgMatches) -> bool {
    matches.is_present("DRYRUN")
}

fn make_org_url(matches: &clap::ArgMatches) -> String {
    let org = matches
        .value_of("ORG")
        .expect("Please specify a github org");

    format!("https://api.github.com/orgs/{}/repos", org)
}

fn get_pr_links(repos: &Vec<github::GithubRepo>, token: &str, reqwest_client: &reqwest::Client, dryrun: bool) -> Vec<Option<String>> {
    let mut pr_links: Vec<Option<String>> = repos
        .into_iter()
        .map(|repo| match get_release_pr_for(&repo, &token, reqwest_client, dryrun) {
            Some(pr_url) => Some(pr_url),
            None => None,
        })
        .collect();
    // only keep the Some(PR_URL) items:
    pr_links.retain(|maybe_pr_link| maybe_pr_link.is_some());
    pr_links
}

fn get_reqwest_client() -> reqwest::Client {
    match reqwest::Client::new() {
        Ok(new_client) => new_client,
        Err(e) => panic!("Couldn't create new reqwest client: {}", e),
    }
}

fn get_repos_we_care_about(token: &str, github_org_url: &str, reqwest_client: &reqwest::Client) -> Vec<github::GithubRepo> {
    let mut repos = match github::get_repos_at(github_org_url, token, reqwest_client) {
        Ok(repos) => repos,
        Err(e) => panic!(format!("Couldn't get repos from github: {}", e)),
    };
    let repos_to_ignore = ignored_repos();

    // remove repos we don't care about:
    repos.retain(|repo| !repos_to_ignore.contains(&repo.name));

    repos
}

fn get_release_pr_for(repo: &github::GithubRepo, token: &str, client: &reqwest::Client, dryrun: bool) -> Option<String> {
    println!("looking for release PR for {}", repo.name);
    match github::existing_release_pr_location(repo, token, client) {
        Some(url) => Some(url),
        None => if !github::is_release_up_to_date_with_master(&repo.url, token, client) {
            if dryrun {
                Some(format!("Dry run: {} would get a release PR.", repo.url))
            } else {
                match github::create_release_pull_request(repo, token, client) {
                    Ok(pr_url) => Some(pr_url),
                    Err(_) => None,
                }
            }
        } else {
            None
        },
    }
}

fn print_party_links(pr_links: Vec<Option<String>>) {
    if !pr_links.is_empty() {
        println!("\nIt's a release party!  PRs to review and approve:");
        for link in pr_links {
            match link {
                Some(pr_link) => println!("{}", pr_link),
                None => println!("Party link is None: this shouldn't happen."),
            }
        }
    } else {
        println!("\nNo party today, all releases are done.");
    }
}

#[derive(Deserialize, Debug)]
struct IgnoredRepo {
    ignore: Option<Vec<String>>,
}

fn ignored_repos() -> Vec<String> {
    let mut f = match File::open("ignoredrepos.toml") {
        Ok(file) => file,
        Err(e) => {
            println!("Couldn't load ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    };
    let mut buffer = String::new();
    match f.read_to_string(&mut buffer) {
        Ok(_) => (),
        Err(e) => {
            println!("Couldn't read from ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    }

    let ignored: IgnoredRepo = match toml::from_str(&buffer) {
        Ok(ignored_repos) => ignored_repos,
        Err(e) => {
            println!(
                "Couldn't parse toml from ignoredrepos.toml, not ignoring any repos. Reason: {}",
                e
            );
            return Vec::new();
        }
    };
    match ignored.ignore {
        Some(repos_to_ignore) => repos_to_ignore,
        None => Vec::new(),
    }
}

fn get_github_token() -> String {
    match env::var(GITHUB_TOKEN) {
        Ok(gh_token) => gh_token,
        Err(e) => panic!(format!("Couldn't find {}: {}", GITHUB_TOKEN, e)),
    }
}

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

    #[test]
    fn token_from_env_happy_path() {
        env::set_var(GITHUB_TOKEN, "a token");
        assert_eq!("a token", get_github_token());
        env::remove_var(GITHUB_TOKEN);
    }

    #[test]
    #[should_panic]
    fn token_from_env_sad_path() {
        env::remove_var(GITHUB_TOKEN);
        get_github_token();
    }
}<commit_msg>Adds another test.<commit_after>#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

#[macro_use]
extern crate clap;
extern crate reqwest;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::env;
use std::io::prelude::*;
use std::fs::File;
use clap::App;

mod github;

static GITHUB_TOKEN: &'static str = "RP_GITHUBTOKEN";

fn main() {
    let yaml = load_yaml!("release-party.yml");
    let matches = App::from_yaml(yaml).get_matches();

    let org_url = make_org_url(&matches);
    let token = get_github_token();
    let reqwest_client = get_reqwest_client();

    print_party_links(get_pr_links(
        &get_repos_we_care_about(&token, &org_url, &reqwest_client),
        &token,
        &reqwest_client,
        is_dryrun(&matches),
    ));
}

fn is_dryrun(matches: &clap::ArgMatches) -> bool {
    matches.is_present("DRYRUN")
}

fn make_org_url(matches: &clap::ArgMatches) -> String {
    let org = matches
        .value_of("ORG")
        .expect("Please specify a github org");

    format!("https://api.github.com/orgs/{}/repos", org)
}

fn get_pr_links(repos: &Vec<github::GithubRepo>, token: &str, reqwest_client: &reqwest::Client, dryrun: bool) -> Vec<Option<String>> {
    let mut pr_links: Vec<Option<String>> = repos
        .into_iter()
        .map(|repo| match get_release_pr_for(&repo, &token, reqwest_client, dryrun) {
            Some(pr_url) => Some(pr_url),
            None => None,
        })
        .collect();
    // only keep the Some(PR_URL) items:
    pr_links.retain(|maybe_pr_link| maybe_pr_link.is_some());
    pr_links
}

fn get_reqwest_client() -> reqwest::Client {
    match reqwest::Client::new() {
        Ok(new_client) => new_client,
        Err(e) => panic!("Couldn't create new reqwest client: {}", e),
    }
}

fn get_repos_we_care_about(token: &str, github_org_url: &str, reqwest_client: &reqwest::Client) -> Vec<github::GithubRepo> {
    let mut repos = match github::get_repos_at(github_org_url, token, reqwest_client) {
        Ok(repos) => repos,
        Err(e) => panic!(format!("Couldn't get repos from github: {}", e)),
    };
    let repos_to_ignore = ignored_repos();

    // remove repos we don't care about:
    repos.retain(|repo| !repos_to_ignore.contains(&repo.name));

    repos
}

fn get_release_pr_for(repo: &github::GithubRepo, token: &str, client: &reqwest::Client, dryrun: bool) -> Option<String> {
    println!("looking for release PR for {}", repo.name);
    match github::existing_release_pr_location(repo, token, client) {
        Some(url) => Some(url),
        None => if !github::is_release_up_to_date_with_master(&repo.url, token, client) {
            if dryrun {
                Some(format!("Dry run: {} would get a release PR.", repo.url))
            } else {
                match github::create_release_pull_request(repo, token, client) {
                    Ok(pr_url) => Some(pr_url),
                    Err(_) => None,
                }
            }
        } else {
            None
        },
    }
}

fn print_party_links(pr_links: Vec<Option<String>>) {
    if !pr_links.is_empty() {
        println!("\nIt's a release party!  PRs to review and approve:");
        for link in pr_links {
            match link {
                Some(pr_link) => println!("{}", pr_link),
                None => println!("Party link is None: this shouldn't happen."),
            }
        }
    } else {
        println!("\nNo party today, all releases are done.");
    }
}

#[derive(Deserialize, Debug)]
struct IgnoredRepo {
    ignore: Option<Vec<String>>,
}

fn ignored_repos() -> Vec<String> {
    let mut f = match File::open("ignoredrepos.toml") {
        Ok(file) => file,
        Err(e) => {
            println!("Couldn't load ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    };
    let mut buffer = String::new();
    match f.read_to_string(&mut buffer) {
        Ok(_) => (),
        Err(e) => {
            println!("Couldn't read from ignoredrepos.toml, not ignoring any repos. Reason: {}", e);
            return Vec::new();
        }
    }

    let ignored: IgnoredRepo = match toml::from_str(&buffer) {
        Ok(ignored_repos) => ignored_repos,
        Err(e) => {
            println!(
                "Couldn't parse toml from ignoredrepos.toml, not ignoring any repos. Reason: {}",
                e
            );
            return Vec::new();
        }
    };
    match ignored.ignore {
        Some(repos_to_ignore) => repos_to_ignore,
        None => Vec::new(),
    }
}

fn get_github_token() -> String {
    match env::var(GITHUB_TOKEN) {
        Ok(gh_token) => gh_token,
        Err(e) => panic!(format!("Couldn't find {}: {}", GITHUB_TOKEN, e)),
    }
}

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

    #[test]
    fn token_from_env_happy_path() {
        env::set_var(GITHUB_TOKEN, "a token");
        assert_eq!("a token", get_github_token());
        env::remove_var(GITHUB_TOKEN);
    }

    #[test]
    #[should_panic]
    fn token_from_env_sad_path() {
        env::remove_var(GITHUB_TOKEN);
        get_github_token();
    }

    #[test]
    fn get_ignored_repos_happy_path() {
        let ignored_repositories = vec!["calagator".to_owned(), "moe".to_owned()];
        assert_eq!(ignored_repositories, ignored_repos());
    }
}<|endoftext|>


<commit_before>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".to_string()),
            twitter: Value("@coredump_ch".to_string()),
            foursquare: Value("525c20e5498e875d8231b1e5".to_string()),
            email: Value("vorstand@lists.coredump.ch".to_string()),
        },
        vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".to_string()),
            url: "https://www.coredump.ch/feed/".to_string(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".to_string(),
        "https://discourse.coredump.ch/c/projects".to_string(),
        "https://github.com/coredump-ch/".to_string(),
    ]);
    status.state.message = Value("Open every Monday from 20:00".to_string());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".to_string(),
        location: "Hackerspace".to_string(),
        name: Value("Raspberry CPU".to_string()),
        description: Absent,
    }), "raspi_temperature".to_string());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".to_string(),
        location: "Hackerspace".to_string(),
        name: Value("Room Temperature".to_string()),
        description: Absent,
    }), "room_temperature".to_string());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".to_string()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".to_string());

    // Serve!
    server.serve();
}
<commit_msg>Replace to_string() with into() in main<commit_after>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".into()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".into()),
            twitter: Value("@coredump_ch".into()),
            foursquare: Value("525c20e5498e875d8231b1e5".into()),
            email: Value("vorstand@lists.coredump.ch".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".into()),
            url: "https://www.coredump.ch/feed/".into(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".into(),
        "https://discourse.coredump.ch/c/projects".into(),
        "https://github.com/coredump-ch/".into(),
    ]);
    status.state.message = Value("Open every Monday from 20:00".into());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Raspberry CPU".into()),
        description: Absent,
    }), "raspi_temperature".into());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".into(),
        location: "Hackerspace".into(),
        name: Value("Room Temperature".into()),
        description: Absent,
    }), "room_temperature".into());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".into()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".into());

    // Serve!
    server.serve();
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate irc;
extern crate xdg_basedir;
extern crate hyper;

mod github;

use regex::Regex;
use irc::client::prelude::*;
use irc::client::server::NetIrcServer;
use xdg_basedir::*;
use std::io::Read;

fn parse_post(post: &str) -> Option<String> {
    let client = hyper::client::Client::new();
    let urlregex = Regex::new(r"https?://\S+\.[:alpha:]{2,}").unwrap();

    if let Some(x) = urlregex.captures(post) {
        if let Ok(mut resp) = client.get(x.at(0).unwrap()).send() {
            let mut body = String::new();
            resp.read_to_string(&mut body).unwrap();
            let titleregex = Regex::new(r"<title>(.+)</title>").unwrap();
            if let Some(cap) = titleregex.captures(&body) {
                return Some(format!("Title: {}", cap.at(1).unwrap()));
            }
        }
    }

    let issueregex = Regex::new(r"([^ ()]+)/([^ ()]+)#(\d+)").unwrap();
    let cap = match issueregex.captures(post) {
        Some(x) => x,
        None => return None
    };
    let user = cap.at(1).unwrap();
    let repo = cap.at(2).unwrap();
    let number = cap.at(3).unwrap();

    github::get_display_text(user, repo, number).ok()
}

fn handle_message(server: &NetIrcServer, from: &str, to: &str, message: &str) {
    let nickname = server.config().nickname.as_ref().unwrap();

    if to == nickname && from == "ids1024" {
        let mut words = message.split_whitespace();
        let command = words.next().unwrap_or("");
        let parameter = words.next().unwrap_or("");
        match command {
            "join" => {
                server.send_join(parameter).unwrap();
            },
            "part" => {
                server.send(Command::PART(parameter.to_string(), None)).unwrap();
            },
            "quit" => {
                server.send_quit("").unwrap();
            }
            _ => {},
        }
    }

    if let Some(x) = parse_post(&message) {
        for line in x.lines() {
            server.send_privmsg(&to, &line).unwrap();
        }
    }
}

fn main() {
    let mut configpath = get_config_home().unwrap();
    configpath.push("idsbot/config.json");

    let config = Config::load(configpath).unwrap();
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();

    for message in server.iter() {
        let message = message.unwrap();
        print!("{}", message.into_string());
        if message.command == "PRIVMSG" {
            let from = message.get_source_nickname().unwrap().to_owned();
            let to = &message.args[0];
            let content = message.suffix.unwrap();
            handle_message(&server, &from, to, &content);
        }
    }
}
<commit_msg>Use if let instead of match for more consistency<commit_after>extern crate regex;
extern crate irc;
extern crate xdg_basedir;
extern crate hyper;

mod github;

use regex::Regex;
use irc::client::prelude::*;
use irc::client::server::NetIrcServer;
use xdg_basedir::*;
use std::io::Read;

fn parse_post(post: &str) -> Option<String> {
    let client = hyper::client::Client::new();
    let urlregex = Regex::new(r"https?://\S+\.[:alpha:]{2,}").unwrap();

    if let Some(x) = urlregex.captures(post) {
        if let Ok(mut resp) = client.get(x.at(0).unwrap()).send() {
            let mut body = String::new();
            resp.read_to_string(&mut body).unwrap();
            let titleregex = Regex::new(r"<title>(.+)</title>").unwrap();
            if let Some(cap) = titleregex.captures(&body) {
                return Some(format!("Title: {}", cap.at(1).unwrap()));
            }
        }
    }

    let issueregex = Regex::new(r"([^ ()]+)/([^ ()]+)#(\d+)").unwrap();

    if let Some(cap) = issueregex.captures(post) {
        let user = cap.at(1).unwrap();
        let repo = cap.at(2).unwrap();
        let number = cap.at(3).unwrap();
        return github::get_display_text(user, repo, number).ok()
    }
    None
}

fn handle_message(server: &NetIrcServer, from: &str, to: &str, message: &str) {
    let nickname = server.config().nickname.as_ref().unwrap();

    if to == nickname && from == "ids1024" {
        let mut words = message.split_whitespace();
        let command = words.next().unwrap_or("");
        let parameter = words.next().unwrap_or("");
        match command {
            "join" => {
                server.send_join(parameter).unwrap();
            },
            "part" => {
                server.send(Command::PART(parameter.to_string(), None)).unwrap();
            },
            "quit" => {
                server.send_quit("").unwrap();
            }
            _ => {},
        }
    }

    if let Some(x) = parse_post(&message) {
        for line in x.lines() {
            server.send_privmsg(&to, &line).unwrap();
        }
    }
}

fn main() {
    let mut configpath = get_config_home().unwrap();
    configpath.push("idsbot/config.json");

    let config = Config::load(configpath).unwrap();
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();

    for message in server.iter() {
        let message = message.unwrap();
        print!("{}", message.into_string());
        if message.command == "PRIVMSG" {
            let from = message.get_source_nickname().unwrap().to_owned();
            let to = &message.args[0];
            let content = message.suffix.unwrap();
            handle_message(&server, &from, to, &content);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>remove main<commit_after><|endoftext|>


<commit_before>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
enum Token {
    Unknown(String), // Invalid test (basically non-ascii)
    Literal(String), // Numeric literal number
    Func(Function), // Pre-defined function (like cos() )
    Const(Constant), // Constant like pi or e
    Var(String), // str arbitrary single char variable name
    Op(Operator), // Any of the 4 operators (+-*/)
    Open, // Open parens '('
    Close, // Closing parens ')'
    Set(Vec<Token>), // [ (, tokens..., ) ]
    Fake,
}

#[derive(Debug, PartialEq, Clone)]
enum Function {
    Sqrt(Vec<Token>),
    Ln(Vec<Token>),
    Log(f64, Vec<Token>),
    Sin(Vec<Token>),
    Cos(Vec<Token>),
    Tan(Vec<Token>),
    Asin(Vec<Token>),
    Acos(Vec<Token>),
    Atan(Vec<Token>),
    Sinh(Vec<Token>),
    Cosh(Vec<Token>),
    Tanh(Vec<Token>),
    Asinh(Vec<Token>),
    Acosh(Vec<Token>),
    Atanh(Vec<Token>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Operator {
    Add,
    Sub,
    Div,
    Mul,
    Pow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

#[derive(Debug, PartialEq, Clone)]
struct Expression {
    tokens: Vec<Token>,
    constant: f64,
}

impl Expression {
	fn new(tokens: Vec<Token>, constant: f64) -> Self {
		Expression {tokens: tokens, constant: constant}
	}

	fn push(&mut self, token: Token) {
		self.tokens.push(token);
	}

	fn update_constant(&mut self, constant: &f64) {
		self.constant += *constant;
	}

	fn get_constant(&self) -> f64 {
		self.constant
	}

	fn get_tokens(&self) -> &[Token] {
		self.tokens.as_slice()
	}

	fn get_mut_tokens(&mut self) -> &mut [Token] {
		self.tokens.as_mut_slice()
	}

	fn replace_token(&mut self, index: usize, newToken: Token) {
		self.tokens.remove(index);
		self.tokens.insert(index, newToken);
	}

	fn replace_all_tokens(&mut self, newTokens: Vec<Token>) {
		self.tokens = newTokens
	}

	fn find_first(&self, token: &Token) -> Option<usize> {
		let mut index: usize = 0;
		for t in &self.tokens {
			if t == token {
				return Some(index);
			}
			index += 1;
		}
		None
	}

	fn find_last(&self, token: &Token) -> Option<usize> {
		let mut index: usize = 0;
		let mut found = false;
		for i in (0..self.tokens.len()).rev() {
			if self.tokens.get(i).unwrap() == token {
				index = i;
				return Some(index);
			}
		}
		None
	}

	fn split_at(&self, index: usize) -> (&[Token], &[Token]) {
		self.tokens.split_at(index)
	}

	fn len(&self) -> usize {
		self.tokens.len()
	}
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        stdin.read_line(&mut input).unwrap();
        input = strip_white_space(&input);
        input = input.to_lowercase();
        if input == "quit" {
        	print!("Exiting...");
        	break;
        }
        let mut expr = parse_input(&input).unwrap();
        println!("{:?}", &expr);
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn parse_input(input: &String) -> Result<Expression, ()> {
	let mut expr: Expression = Expression::new(Vec::new(), 0.0);
	for c in input.chars() {
		match c {
			'-' => {
				expr.push(Token::Op(Operator::Sub));
			},
			'+' => {
				expr.push(Token::Op(Operator::Add));
			},
			'/' => {
				expr.push(Token::Op(Operator::Div));
			},
			'*' => {
				expr.push(Token::Op(Operator::Mul));
			},
			'^' => {
				expr.push(Token::Op(Operator::Pow));
			},
			'(' => {
				expr.push(Token::Open);
			},
			')' => {
				expr.push(Token::Close);
			},
			_ => continue,
		}
	}
	if let Some(index) = expr.find_first(&Token::Open) { // If we find an index of an Open
		let endSet: usize = expr.find_last(&Token::Close).unwrap();
		let mut lhs: Vec<Token> = Vec::new();
		let mut rhs: Vec<Token> = Vec::new();
		{
			let (temp_lhs, temp_rhs) = expr.split_at(index); // [0, where set should be placed)
			lhs = temp_lhs.to_vec();
			rhs = temp_rhs.to_vec(); // [where set should be placed, len)
			rhs.remove(0);
			// split rhs at endset - 2
			// Left part gets pushed as a Set to lhs
			// Remove index 0 of right part (this is the close we split on) and add that as a vector to lhs
			let (mut left_rhs, mut right_rhs) = rhs.split_at(endSet-2);
			let (mut left_rhs, mut right_rhs) = (left_rhs.to_vec(), right_rhs.to_vec());
			right_rhs.remove(0);
			//rhs.remove(endSet-2); // Sub one because we removed the first element, need to split at endSet -2
			lhs.push(Token::Set(left_rhs));
			lhs.append(&mut right_rhs);
		}
		for i in (0..lhs.len()).rev() {
			if lhs.get(i).unwrap() == &Token::Close {
				lhs.remove(i);
				break;
			}
		}
		expr.replace_all_tokens(lhs);
	}
	Ok(expr)
}<commit_msg>Unused variables<commit_after>use std::io;
use std::io::Write;

#[derive(Debug, PartialEq, Clone)]
enum Token {
    Unknown(String), // Invalid test (basically non-ascii)
    Literal(String), // Numeric literal number
    Func(Function), // Pre-defined function (like cos() )
    Const(Constant), // Constant like pi or e
    Var(String), // str arbitrary single char variable name
    Op(Operator), // Any of the 4 operators (+-*/)
    Open, // Open parens '('
    Close, // Closing parens ')'
    Set(Vec<Token>), // [ (, tokens..., ) ]
    Fake,
}

#[derive(Debug, PartialEq, Clone)]
enum Function {
    Sqrt(Vec<Token>),
    Ln(Vec<Token>),
    Log(f64, Vec<Token>),
    Sin(Vec<Token>),
    Cos(Vec<Token>),
    Tan(Vec<Token>),
    Asin(Vec<Token>),
    Acos(Vec<Token>),
    Atan(Vec<Token>),
    Sinh(Vec<Token>),
    Cosh(Vec<Token>),
    Tanh(Vec<Token>),
    Asinh(Vec<Token>),
    Acosh(Vec<Token>),
    Atanh(Vec<Token>),
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Constant {
	Pi,
	E,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Operator {
    Add,
    Sub,
    Div,
    Mul,
    Pow,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum Assoc {
    Left,
    Right,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum Order {
    AddSub = 1,
    MulDiv = 2,
    IMul = 3, // Implicit multiplication
    Pow = 4,
    Paren = 5,
}

#[derive(Debug, PartialEq, Clone)]
struct Expression {
    tokens: Vec<Token>,
    constant: f64,
}

impl Expression {
	fn new(tokens: Vec<Token>, constant: f64) -> Self {
		Expression {tokens: tokens, constant: constant}
	}

	fn push(&mut self, token: Token) {
		self.tokens.push(token);
	}

	fn update_constant(&mut self, constant: &f64) {
		self.constant += *constant;
	}

	fn get_constant(&self) -> f64 {
		self.constant
	}

	fn get_tokens(&self) -> &[Token] {
		self.tokens.as_slice()
	}

	fn get_mut_tokens(&mut self) -> &mut [Token] {
		self.tokens.as_mut_slice()
	}

	fn replace_token(&mut self, index: usize, newToken: Token) {
		self.tokens.remove(index);
		self.tokens.insert(index, newToken);
	}

	fn replace_all_tokens(&mut self, newTokens: Vec<Token>) {
		self.tokens = newTokens
	}

	fn find_first(&self, token: &Token) -> Option<usize> {
		for i in 0..self.tokens.len() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn find_last(&self, token: &Token) -> Option<usize> {
		for i in (0..self.tokens.len()).rev() {
			if self.tokens.get(i).unwrap() == token {
				return Some(i);
			}
		}
		None
	}

	fn split_at(&self, index: usize) -> (&[Token], &[Token]) {
		self.tokens.split_at(index)
	}

	fn len(&self) -> usize {
		self.tokens.len()
	}
}

fn main() {
    println!("Welcome to Rust-Calculus!");
    println!("To evaluate an expression, simply type one in and hit RETURN.");
    println!("To set a variable, simply type VAR_NAME=EXPRESSION and hit RETURN.");
    println!("Valid commands are: sym_int, int, sym_def, and def.");
    println!("Type 'quit' to exit.");
    let mut input = String::new();
    let stdin = io::stdin();
    let mut stdout = io::stdout();
    loop {
    	input.clear();
    	print!(">>>> ");
    	stdout.flush().ok();
        stdin.read_line(&mut input).unwrap();
        input = strip_white_space(&input);
        input = input.to_lowercase();
        if input == "quit" {
        	print!("Exiting...");
        	break;
        }
        let mut expr = parse_input(&input).unwrap();
        println!("{:?}", &expr);
    }
}

fn strip_white_space(input: &String) -> String {
	input.split_whitespace().collect::<Vec<&str>>().join("")
}

fn parse_input(input: &String) -> Result<Expression, ()> {
	let mut expr: Expression = Expression::new(Vec::new(), 0.0);
	for c in input.chars() {
		match c {
			'-' => {
				expr.push(Token::Op(Operator::Sub));
			},
			'+' => {
				expr.push(Token::Op(Operator::Add));
			},
			'/' => {
				expr.push(Token::Op(Operator::Div));
			},
			'*' => {
				expr.push(Token::Op(Operator::Mul));
			},
			'^' => {
				expr.push(Token::Op(Operator::Pow));
			},
			'(' => {
				expr.push(Token::Open);
			},
			')' => {
				expr.push(Token::Close);
			},
			_ => continue,
		}
	}
	if let Some(index) = expr.find_first(&Token::Open) { // If we find an index of an Open
		let endSet: usize = expr.find_last(&Token::Close).unwrap();
		let mut lhs: Vec<Token> = Vec::new();
		let mut rhs: Vec<Token> = Vec::new();
		{
			let (temp_lhs, temp_rhs) = expr.split_at(index); // [0, where set should be placed)
			lhs = temp_lhs.to_vec();
			rhs = temp_rhs.to_vec(); // [where set should be placed, len)
			rhs.remove(0);
			// split rhs at endset - 2
			// Left part gets pushed as a Set to lhs
			// Remove index 0 of right part (this is the close we split on) and add that as a vector to lhs
			let (mut left_rhs, mut right_rhs) = rhs.split_at(endSet-2);
			let (mut left_rhs, mut right_rhs) = (left_rhs.to_vec(), right_rhs.to_vec());
			right_rhs.remove(0);
			//rhs.remove(endSet-2); // Sub one because we removed the first element, need to split at endSet -2
			lhs.push(Token::Set(left_rhs));
			lhs.append(&mut right_rhs);
		}
		for i in (0..lhs.len()).rev() {
			if lhs.get(i).unwrap() == &Token::Close {
				lhs.remove(i);
				break;
			}
		}
		expr.replace_all_tokens(lhs);
	}
	Ok(expr)
}<|endoftext|>


<commit_before>#![feature(io)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a + b);
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x + i);
            }
            &Mov(n) => {
                self.index += n
            }
            &In => {
                let mut c = vec![0u8];
                io::stdin().read(&mut c).unwrap();
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<commit_msg>chore: use wrapping operations<commit_after>#![feature(core, io)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                io::stdin().read(&mut c).unwrap();
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<|endoftext|>


<commit_before>extern crate itertools;
mod cpu;

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

fn main() {
	let mut cpu = cpu::Core::new_mem(0x40, &[0xc3, 0x00]);
	cpu.ophandlers = cpu::ops::instruction_set();
	cpu.dar[0] = 0x16;
	cpu.dar[1] = 0x26;
	cpu.execute1();
    println!("Hello, CPU at {}", cpu.pc);
    match write_state(&cpu) {
    	Ok(_) => return (),
    	Err(e) => panic!(e),
    };
}

fn write_state(core: &cpu::Core) -> Result<()> {
	let mut buffer = try!(File::create("cpustate.txt"));
	let dxs = (0..8).map(|i| format!("D{}:{:08x}", i, core.dar[i])).join(" ");
	let axs = (0..8).map(|i| format!("A{}:{:08x}", i, core.dar[i+8])).join(" ");
	try!(writeln!(buffer, "PC:{:08x} SP:{:08x} SR:{:08x} FL:{} {} {}", core.pc, core.sp, core.status_register(), core.flags(), dxs, axs));
	Ok(())
}

// cpu state (all registers, flags etc.)
// initialize
//      m68ki_build_opcode_table();
//		m68ki_jump(0);
//		REG_SP = m68ki_read_imm_32();
//		REG_PC = m68ki_read_imm_32();
//		m68ki_jump(REG_PC);

// execute instruction (modifies CPU state)
/*
			/* Record previous program counter */
			REG_PPC = REG_PC;

			/* Read an instruction and call its handler */
			REG_IR = m68ki_read_imm_16();
			// include all 64k entries?
			m68ki_instruction_jump_table[REG_IR]();
			USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
*/

<commit_msg>Remove clipboard comments<commit_after>extern crate itertools;
mod cpu;

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

fn main() {
	let mut cpu = cpu::Core::new_mem(0x40, &[0xc3, 0x00]);
	cpu.ophandlers = cpu::ops::instruction_set();
	cpu.dar[0] = 0x16;
	cpu.dar[1] = 0x26;
	cpu.execute1();
    println!("Hello, CPU at {}", cpu.pc);
    match write_state(&cpu) {
    	Ok(_) => return (),
    	Err(e) => panic!(e),
    };
}

fn write_state(core: &cpu::Core) -> Result<()> {
	let mut buffer = try!(File::create("cpustate.txt"));
	let dxs = (0..8).map(|i| format!("D{}:{:08x}", i, core.dar[i])).join(" ");
	let axs = (0..8).map(|i| format!("A{}:{:08x}", i, core.dar[i+8])).join(" ");
	try!(writeln!(buffer, "PC:{:08x} SP:{:08x} SR:{:08x} FL:{} {} {}", core.pc, core.sp, core.status_register(), core.flags(), dxs, axs));
	Ok(())
}

<|endoftext|>


<commit_before>extern crate orbclient;

use orbclient::BmpFile;

use super::{CloneCell, Color, CopyCell, Event, Place, Point, Rect, Renderer, Widget, Window};
use super::callback::Click;

pub struct Menu {
    rect: Rect,
    fg: Color,
    actions: Vec<Action>,
}

pub struct Action {
    rect: CopyCell<Rect>,
    text: CloneCell<String>,
    icon: Option<BmpFile>,
    bg_up: Color,
    bg_down: Color,
    click_callback: Option<Arc<Fn()>>,
    pressed: CopyCell<bool>,
}

impl Menu {
    pub fn new() -> Self {
        Menu {
            rect: Rect::default(),
            fg: Color::rgb(0, 0, 0),
            actions: Vec::with_capacity(1),
        }
    }

    pub fn add_action(&mut self, name: &str, icon: Option<BmpFile>) {
        self.actions.insert(Action::new(name), icon);
    }
}

impl Action {
    pub fn new(text: &str) -> Self {
        Action {
            rect: Rect::default(),
            text: CloneCell::new(name.to_owned()),
            icon: None,
            bg_up: Color::rgb(220, 222, 227),
            bg_down: Color::rgb(203, 205, 210),
            click_callback: None,
            pressed: CopyCell::new(false),
        }
    }

    pub fn add_icon(mut self, icon: BmpFile) -> Self {
        self.icon = Some(icon);
        self
    }
}
<commit_msg>Add `Entry` trait and cleanup<commit_after>extern crate orbclient;

use orbclient::BmpFile;

use super::{CloneCell, Color, CopyCell, Event, Place, Point, Rect, Renderer, Widget, Window};
use super::callback::Click;

pub struct Menu {
    rect: CopyCell<Rect>,
    text: CloneCell<String>,
    fg: Color,
    entries: Vec<Box<Entry>>,
}

pub struct Action {
    rect: CopyCell<Rect>,
    text: CloneCell<String>,
    icon: Option<BmpFile>,
    bg_up: Color,
    bg_down: Color,
    click_callback: Option<Arc<Fn()>>,
    pressed: CopyCell<bool>,
}

pub struct Separator;

pub trait Entry {
    fn text<S: AsRef<str>>(&mut self) -> S;
}

impl Menu {
    pub fn new(name: &str) -> Self {
        Menu {
            rect: Rect::default(),
            text: CloneCell::new(name.to_owned()),
            fg: Color::rgb(0, 0, 0),
            entries: Vec::with_capacity(10),
        }
    }

    pub fn add_entry<E: Entry>(mut self, entry: E) -> Self {
        self.actions.insert(entry);
        self
    }
}

impl Action {
    pub fn new(text: &str) -> Self {
        Action {
            rect: Rect::default(),
            text: CloneCell::new(name.to_owned()),
            icon: None,
            bg_up: Color::rgb(220, 222, 227),
            bg_down: Color::rgb(203, 205, 210),
            click_callback: None,
            pressed: CopyCell::new(false),
        }
    }

    pub fn add_icon(mut self, icon: BmpFile) -> Self {
        self.icon = Some(icon);
        self
    }
}

impl Widget for Action {
    fn draw(&self, renderer: &mut Renderer, _focused: bool) {
        let rect = self.rect.get();

        if self.pressed.get() {
            renderer.rect(rect, self.bg_down);
        } else {
            renderer.rect(rect, self.bg_up);
        }

        let text = self.text.borrow();

        let mut x = 0;
        let mut y = 0;
        for c in text.chars() {
            if c == '\n' {
                x = 0;
                y += 16;
            } else {
                if x + 8 <= rect.width as i32 && y + 16 <= rect.height as i32 {
                    renderer.char(Point::new(x, y) + rect.point(), c, self.fg);
                }
                x += 8;
            }
        }
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
        }
    }
}

impl Entry for Menu {
    fn text<S: AsRef<str>>(&mut self) -> S {
        self.text.get()
    }
}

impl Entry for Action {
    fn text<S: AsRef<str>>(&mut self) -> S {
        self.text.get()
    }
}

impl Entry for Separator {
    fn text<S: AsRef<str>>(&mut self) -> S {
        "separator"
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::io::{self, Read, Write};

use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};

#[derive(Debug)]
pub struct Buf {
    vec: Vec<u8>,
    pos: usize,
}

impl Buf {
    pub fn new() -> Buf {
        Buf::wrap(vec![])
    }

    pub fn wrap(vec: Vec<u8>) -> Buf {
        Buf {
            vec: vec,
            pos: 0,
        }
    }
}

impl ::std::ops::Deref for Buf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.vec
    }
}

impl<S: AsRef<[u8]>> PartialEq<S> for Buf {
    fn eq(&self, other: &S) -> bool {
        self.vec == other.as_ref()
    }
}

impl Write for Buf {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        self.vec.extend(data);
        Ok(data.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Read for Buf {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&self.vec[self.pos..]).read(buf).map(|n| {
            self.pos += n;
            n
        })
    }
}

#[derive(Debug)]
pub struct AsyncIo<T> {
    inner: T,
    bytes_until_block: usize,
    error: Option<io::Error>,
    blocked: bool,
    flushed: bool,
}

impl<T> AsyncIo<T> {
    pub fn new(inner: T, bytes: usize) -> AsyncIo<T> {
        AsyncIo {
            inner: inner,
            bytes_until_block: bytes,
            error: None,
            flushed: false,
            blocked: false,
        }
    }

    pub fn block_in(&mut self, bytes: usize) {
        self.bytes_until_block = bytes;
    }

    pub fn error(&mut self, err: io::Error) {
        self.error = Some(err);
    }
}

impl AsyncIo<Buf> {
    #[cfg(feature = "tokio-proto")]
    //TODO: fix proto::conn::tests to not use tokio-proto API,
    //and then this cfg flag go away
    pub fn new_buf<T: Into<Vec<u8>>>(buf: T, bytes: usize) -> AsyncIo<Buf> {
        AsyncIo::new(Buf::wrap(buf.into()), bytes)
    }

    #[cfg(feature = "tokio-proto")]
    //TODO: fix proto::conn::tests to not use tokio-proto API,
    //and then this cfg flag go away
    pub fn new_eof() -> AsyncIo<Buf> {
        AsyncIo::new(Buf::wrap(Vec::new().into()), 1)
    }

    #[cfg(feature = "tokio-proto")]
    //TODO: fix proto::conn::tests to not use tokio-proto API,
    //and then this cfg flag go away
    pub fn flushed(&self) -> bool {
        self.flushed
    }

    pub fn blocked(&self) -> bool {
        self.blocked
    }
}

impl<T: Read> Read for AsyncIo<T> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.blocked = false;
        if let Some(err) = self.error.take() {
            Err(err)
        } else if self.bytes_until_block == 0 {
            self.blocked = true;
            Err(io::ErrorKind::WouldBlock.into())
        } else {
            let n = cmp::min(self.bytes_until_block, buf.len());
            let n = try!(self.inner.read(&mut buf[..n]));
            self.bytes_until_block -= n;
            Ok(n)
        }
    }
}

impl<T: Write> Write for AsyncIo<T> {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if let Some(err) = self.error.take() {
            Err(err)
        } else if self.bytes_until_block == 0 {
            Err(io::ErrorKind::WouldBlock.into())
        } else {
            trace!("AsyncIo::write() block_in = {}, data.len() = {}", self.bytes_until_block, data.len());
            self.flushed = false;
            let n = cmp::min(self.bytes_until_block, data.len());
            let n = try!(self.inner.write(&data[..n]));
            self.bytes_until_block -= n;
            Ok(n)
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.flushed = true;
        self.inner.flush()
    }
}

impl<T: Read + Write> AsyncRead for AsyncIo<T> {
}

impl<T: Read + Write> AsyncWrite for AsyncIo<T> {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(().into())
    }
}

impl ::std::ops::Deref for AsyncIo<Buf> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.inner
    }
}
<commit_msg>chore(tests): fix tests when tokio-proto feature disabled<commit_after>use std::cmp;
use std::io::{self, Read, Write};

use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};

#[derive(Debug)]
pub struct Buf {
    vec: Vec<u8>,
    pos: usize,
}

impl Buf {
    pub fn new() -> Buf {
        Buf::wrap(vec![])
    }

    pub fn wrap(vec: Vec<u8>) -> Buf {
        Buf {
            vec: vec,
            pos: 0,
        }
    }
}

impl ::std::ops::Deref for Buf {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.vec
    }
}

impl<S: AsRef<[u8]>> PartialEq<S> for Buf {
    fn eq(&self, other: &S) -> bool {
        self.vec == other.as_ref()
    }
}

impl Write for Buf {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        self.vec.extend(data);
        Ok(data.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Read for Buf {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&self.vec[self.pos..]).read(buf).map(|n| {
            self.pos += n;
            n
        })
    }
}

#[derive(Debug)]
pub struct AsyncIo<T> {
    inner: T,
    bytes_until_block: usize,
    error: Option<io::Error>,
    blocked: bool,
    flushed: bool,
}

impl<T> AsyncIo<T> {
    pub fn new(inner: T, bytes: usize) -> AsyncIo<T> {
        AsyncIo {
            inner: inner,
            bytes_until_block: bytes,
            error: None,
            flushed: false,
            blocked: false,
        }
    }

    pub fn block_in(&mut self, bytes: usize) {
        self.bytes_until_block = bytes;
    }

    pub fn error(&mut self, err: io::Error) {
        self.error = Some(err);
    }
}

impl AsyncIo<Buf> {
    pub fn new_buf<T: Into<Vec<u8>>>(buf: T, bytes: usize) -> AsyncIo<Buf> {
        AsyncIo::new(Buf::wrap(buf.into()), bytes)
    }

    #[cfg(feature = "tokio-proto")]
    //TODO: fix proto::conn::tests to not use tokio-proto API,
    //and then this cfg flag go away
    pub fn new_eof() -> AsyncIo<Buf> {
        AsyncIo::new(Buf::wrap(Vec::new().into()), 1)
    }

    #[cfg(feature = "tokio-proto")]
    //TODO: fix proto::conn::tests to not use tokio-proto API,
    //and then this cfg flag go away
    pub fn flushed(&self) -> bool {
        self.flushed
    }

    pub fn blocked(&self) -> bool {
        self.blocked
    }
}

impl<T: Read> Read for AsyncIo<T> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.blocked = false;
        if let Some(err) = self.error.take() {
            Err(err)
        } else if self.bytes_until_block == 0 {
            self.blocked = true;
            Err(io::ErrorKind::WouldBlock.into())
        } else {
            let n = cmp::min(self.bytes_until_block, buf.len());
            let n = try!(self.inner.read(&mut buf[..n]));
            self.bytes_until_block -= n;
            Ok(n)
        }
    }
}

impl<T: Write> Write for AsyncIo<T> {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if let Some(err) = self.error.take() {
            Err(err)
        } else if self.bytes_until_block == 0 {
            Err(io::ErrorKind::WouldBlock.into())
        } else {
            trace!("AsyncIo::write() block_in = {}, data.len() = {}", self.bytes_until_block, data.len());
            self.flushed = false;
            let n = cmp::min(self.bytes_until_block, data.len());
            let n = try!(self.inner.write(&data[..n]));
            self.bytes_until_block -= n;
            Ok(n)
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.flushed = true;
        self.inner.flush()
    }
}

impl<T: Read + Write> AsyncRead for AsyncIo<T> {
}

impl<T: Read + Write> AsyncWrite for AsyncIo<T> {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(().into())
    }
}

impl ::std::ops::Deref for AsyncIo<Buf> {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.inner
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[link(name = "sax",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/sax-rs")];

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_type = "lib"];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::hashmap::HashMap;
use std::libc::{c_char, c_int};
use std::str;

pub mod error;
pub mod ffi;
mod extfn;

#[deriving(Eq, Clone)]
pub enum ParseMsg {
    StartDocument,
    EndDocument,
    StartElement(~str, Attributes),
    EndElement(~str),
    Characters(~str),
    IgnorableWhitespace(~str),
    Comment(~str),
    CdataBlock(~str),
}

impl ToStr for ParseMsg {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => fmt!("<%s%s>", *name, atts.to_str()),
            EndElement(ref name) => fmt!("</%s>", *name),
            Characters(ref ch) => ch.clone(),
            IgnorableWhitespace(_) => ~"",
            Comment(ref value) => fmt!("", *value),
            CdataBlock(ref value) => fmt!("<![CDATA[%s]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attributes(HashMap<~str, ~str>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut map = Attributes(HashMap::new());
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            map.insert(str::raw::from_c_str(*ptr),
                       str::raw::from_c_str(*(ptr + 1)));
            ptr = ptr + 2;
        }
        map
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        do self.iter().map |(k, v)| {
            fmt!(" %s=\"%s\"", *k, *v)
        }.to_owned_vec().concat()
    }
}

pub type ParseResult = Result<ParseMsg, error::ErrorData>;

pub struct Parser {
    priv port: Port<ParseResult>,
    priv is_last: bool,
}

impl Parser {
    /// Recives a new parse result. Fails if the parser has finished.
    pub fn recv(&self) -> ParseResult {
        self.port.try_recv().expect(
            "Could not get a new parse result, the parser has already finished!"
        )
    }

    pub fn try_recv(&self) -> Option<ParseResult> {
        self.port.try_recv()
    }
}

impl Iterator<ParseResult> for Parser {
    #[inline]
    fn next(&mut self) -> Option<ParseResult> {
        if self.is_last { return None };

        let msg = self.try_recv();
        if msg == Some(Ok(EndDocument)) {
            self.is_last = true;
        }
        msg
    }
}

pub fn parse(src: &str) -> Parser {
    let (port, chan) = stream();
    unsafe {
        do src.to_c_str().with_ref |c_str| {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       cast::transmute(&chan),
                                       c_str,
                                       src.len() as c_int);
            ffi::xmlCleanupParser();
        }
    }
    Parser { port: port, is_last: false }
}

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

    static TEST_XML: &'static str = "<hello><this />test</hello>";

    #[test]
    fn test() {
        for r in parse(TEST_XML) {
            match r {
                Ok(IgnorableWhitespace(_)) => (),
                Ok(ref msg) => println(msg.to_str()),
                Err(ref err) => println(err.to_str()),
            }
        }
    }
}
<commit_msg>Impl GenericPort for Parser and remove Iterator impl<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[link(name = "sax",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/sax-rs")];

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_type = "lib"];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::hashmap::HashMap;
use std::libc::{c_char, c_int};
use std::str;

pub mod error;
pub mod ffi;
mod extfn;

#[deriving(Eq, Clone)]
pub enum ParseMsg {
    StartDocument,
    EndDocument,
    StartElement(~str, Attributes),
    EndElement(~str),
    Characters(~str),
    IgnorableWhitespace(~str),
    Comment(~str),
    CdataBlock(~str),
}

impl ToStr for ParseMsg {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => fmt!("<%s%s>", *name, atts.to_str()),
            EndElement(ref name) => fmt!("</%s>", *name),
            Characters(ref ch) => ch.clone(),
            IgnorableWhitespace(_) => ~"",
            Comment(ref value) => fmt!("", *value),
            CdataBlock(ref value) => fmt!("<![CDATA[%s]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attributes(HashMap<~str, ~str>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut map = Attributes(HashMap::new());
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            map.insert(str::raw::from_c_str(*ptr),
                       str::raw::from_c_str(*(ptr + 1)));
            ptr = ptr + 2;
        }
        map
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        do self.iter().map |(k, v)| {
            fmt!(" %s=\"%s\"", *k, *v)
        }.to_owned_vec().concat()
    }
}

pub type ParseResult = Result<ParseMsg, error::ErrorData>;

pub struct Parser {
    priv port: Port<ParseResult>,
}

impl GenericPort<ParseResult> for Parser {
    /// Recives a new parse result. Fails if the parser has finished. Failure
    /// can be avoided by finishing after recieving the `Ok(EndDocument)` result.
    pub fn recv(&self) -> ParseResult {
        self.port.try_recv().expect(
            "Could not get a new parse result, the parser has already finished!"
        )
    }

    pub fn try_recv(&self) -> Option<ParseResult> {
        self.port.try_recv()
    }
}

pub fn parse(src: &str) -> Parser {
    let (port, chan) = stream();
    unsafe {
        do src.to_c_str().with_ref |c_str| {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       cast::transmute(&chan),
                                       c_str,
                                       src.len() as c_int);
            ffi::xmlCleanupParser();
        }
    }
    Parser { port: port }
}

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

    static TEST_XML: &'static str = "<hello><this />test</hello>";

    #[test]
    fn test() {
        let sax = parse(TEST_XML);
        loop {
            let msg = sax.recv().unwrap();
            println(msg.to_str());
            if msg == EndDocument { break }
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std;
use libc::c_char;

use std::io::Write;
use std::io::stdout;

use nom::*;

use tls_parser::tls::{TlsMessage,TlsMessageHandshake,tls_parser_many};
use tls_parser::tls_ciphers::TlsCipherSuite;
use tls_parser::tls_extensions::parse_tls_extensions;
use der_parser::der::parse_der;

pub struct TlsParserState<'a> {
    pub o: Option<&'a[u8]>,

    cipher: u16,
}

impl<'a> TlsParserState<'a> {
    pub fn new(i: &'a[u8]) -> TlsParserState<'a> {
        TlsParserState{o:Some(i),cipher:0}
    }

    fn send(&self, value: i32) -> bool {
        println!("=============================================================");
        println!("inner send: {}", value);
        println!("o: {:?}", self.o);
        println!("cipher: {:?}", self.cipher);
        println!("=============================================================");
        let _ = stdout().flush();
        true
    }
}

impl<'a> Drop for TlsParserState<'a> {
    fn drop(&mut self) {
        println!("DROP");
    }
}

#[no_mangle]
pub extern "C" fn rusticata_new_tls_parser_state<'a>() -> Box<TlsParserState<'a>> {
    Box::new(TlsParserState::new(b"blah"))
}

#[no_mangle]
pub extern fn rusticata_free_tls_parser_state<'a>(_: Box<TlsParserState<'a>>)
{
    println!("rusticata_free_tls_parser_state()");
}

#[no_mangle]
pub extern fn rusticata_use_tls_parser_state<'a>(this: &TlsParserState<'a>, value: i32) -> bool
{
    println!("rusticata_use_tls_parser_state({:?})", value);
    this.send(value)
}

#[no_mangle]
pub extern "C" fn rusticata_parse_der(value: *const c_char, len: u32) -> i32 {
    SCLogDebug!("[rust] rusticata_parse_der");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    let d = parse_der(data);
    SCLogDebug!(format!("d: {:?}", d).as_str());

    0
}

#[no_mangle]
pub extern "C" fn rusticata_tls_decode<'a>(direction: u8, value: *const c_char, len: u32, this: &'a mut TlsParserState<'a>) -> &'a mut TlsParserState<'a> {
    SCLogDebug!("[rust] suri_tls_decode");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    SCLogDebug!(format!("  direction: {}\0", direction).as_str());
    SCLogDebug!(format!("  len: {}\0", data_len).as_str());
    SCLogDebug!(format!("  data: {:?}\0", data).as_str());

    let d = tls_parser_many(data);
    SCLogDebug!(format!("d: {:?}\0", d).as_str());

    // XXX match d with nom::IResult::Done, check if ServerHello, and print selected cipher
    match d {
        IResult::Done(rem,p) => {
            SCLogDebug!(format!("TLS parser successful {} element(s)\0", p.len()).as_str());
            for ref record in &p {
                SCLogDebug!(format!("{:?}\0", record).as_str());
                match record.msg {
                    TlsMessage::Handshake(ref m) => {
                        match *m {
                            TlsMessageHandshake::ClientHello(ref content) => {
                                let blah = parse_tls_extensions(content.ext);
                                SCLogDebug!(format!("ext {:?}\0", blah).as_str());
                            },
                            TlsMessageHandshake::ServerHello(ref content) => {
                                this.cipher = content.cipher;
                                let lu /* cipher */ : TlsCipherSuite = content.cipher.into();
                                SCLogDebug!(format!("Selected cipher: {:?}\0", lu).as_str());
                                let blah = parse_tls_extensions(content.ext);
                                SCLogDebug!(format!("ext {:?}\0", blah).as_str());
                            },
                            _ => (),
                        }
                    },
                    _ => (),
                }
            }
            if rem.len() > 0 { SCLogWarning!(format!("** unparsed ** {:?}\0",rem).as_str()); };
        },
        IResult::Error(e) => SCLogError!(format!("TLS parser reported an error: {:?}\0", e).as_str()),
        IResult::Incomplete(e) => SCLogError!(format!("TLS parser reported incomplete input: {:?}\0", e).as_str()),
    };

    this
}
<commit_msg>Check heartbeat messages, warn on heartbleed attempts<commit_after>extern crate libc;

use std;
use libc::c_char;

use std::io::Write;
use std::io::stdout;

use nom::*;

use tls_parser::tls::{TlsMessage,TlsMessageHandshake,tls_parser_many};
use tls_parser::tls_ciphers::TlsCipherSuite;
use tls_parser::tls_extensions::parse_tls_extensions;
use der_parser::der::parse_der;

pub struct TlsParserState<'a> {
    pub o: Option<&'a[u8]>,

    cipher: u16,
}

impl<'a> TlsParserState<'a> {
    pub fn new(i: &'a[u8]) -> TlsParserState<'a> {
        TlsParserState{o:Some(i),cipher:0}
    }

    fn send(&self, value: i32) -> bool {
        println!("=============================================================");
        println!("inner send: {}", value);
        println!("o: {:?}", self.o);
        println!("cipher: {:?}", self.cipher);
        println!("=============================================================");
        let _ = stdout().flush();
        true
    }
}

impl<'a> Drop for TlsParserState<'a> {
    fn drop(&mut self) {
        println!("DROP");
    }
}

#[no_mangle]
pub extern "C" fn rusticata_new_tls_parser_state<'a>() -> Box<TlsParserState<'a>> {
    Box::new(TlsParserState::new(b"blah"))
}

#[no_mangle]
pub extern fn rusticata_free_tls_parser_state<'a>(_: Box<TlsParserState<'a>>)
{
    println!("rusticata_free_tls_parser_state()");
}

#[no_mangle]
pub extern fn rusticata_use_tls_parser_state<'a>(this: &TlsParserState<'a>, value: i32) -> bool
{
    println!("rusticata_use_tls_parser_state({:?})", value);
    this.send(value)
}

#[no_mangle]
pub extern "C" fn rusticata_parse_der(value: *const c_char, len: u32) -> i32 {
    SCLogDebug!("[rust] rusticata_parse_der");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    let d = parse_der(data);
    SCLogDebug!(format!("d: {:?}", d).as_str());

    0
}

#[no_mangle]
pub extern "C" fn rusticata_tls_decode<'a>(direction: u8, value: *const c_char, len: u32, this: &'a mut TlsParserState<'a>) -> &'a mut TlsParserState<'a> {
    SCLogDebug!("[rust] suri_tls_decode");

    let data_len = len as usize;
    let data : &[u8] = unsafe { std::slice::from_raw_parts(value as *mut u8, data_len) };

    SCLogDebug!(format!("  direction: {}\0", direction).as_str());
    SCLogDebug!(format!("  len: {}\0", data_len).as_str());
    SCLogDebug!(format!("  data: {:?}\0", data).as_str());

    let d = tls_parser_many(data);
    SCLogDebug!(format!("d: {:?}\0", d).as_str());

    // XXX match d with nom::IResult::Done, check if ServerHello, and print selected cipher
    match d {
        IResult::Done(rem,p) => {
            SCLogDebug!(format!("TLS parser successful {} element(s)\0", p.len()).as_str());
            for ref record in &p {
                SCLogDebug!(format!("{:?}\0", record).as_str());
                match record.msg {
                    TlsMessage::Handshake(ref m) => {
                        match *m {
                            TlsMessageHandshake::ClientHello(ref content) => {
                                let blah = parse_tls_extensions(content.ext);
                                SCLogDebug!(format!("ext {:?}\0", blah).as_str());
                            },
                            TlsMessageHandshake::ServerHello(ref content) => {
                                this.cipher = content.cipher;
                                let lu /* cipher */ : TlsCipherSuite = content.cipher.into();
                                SCLogDebug!(format!("Selected cipher: {:?}\0", lu).as_str());
                                let blah = parse_tls_extensions(content.ext);
                                SCLogDebug!(format!("ext {:?}\0", blah).as_str());
                            },
                            _ => (),
                        }
                    },
                    TlsMessage::Heartbeat(ref d) => {
                        if d.payload_len as usize > d.payload.len() {
                            SCLogWarning!(format!("Heartbeat message with incorrect length {}. Heartbleed attempt ?\0",d.payload.len()).as_str());
                        }
                    },
                    _ => (),
                }
            }
            if rem.len() > 0 { SCLogWarning!(format!("** unparsed ** {:?}\0",rem).as_str()); };
        },
        IResult::Error(e) => SCLogError!(format!("TLS parser reported an error: {:?}\0", e).as_str()),
        IResult::Incomplete(e) => SCLogError!(format!("TLS parser reported incomplete input: {:?}\0", e).as_str()),
    };

    this
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Write;

use super::lexer::Lexer;
use super::token::TokenType;

const PROMPT: &'static str = ">> ";

pub fn start<R, W>(mut in_: R, mut out: W)
    where R: Read,
          W: Write
{
    loop {
        print!("{}", PROMPT);
        out.flush().unwrap();

        let mut s = String::new();
        in_.read_to_string(&mut s).expect("Did not enter a correct string");

        let mut l = Lexer::new(s);
        let mut tok = l.next_token();
        while tok.token_type != TokenType::EOF {
            write!(&mut out, "{:?}\n", tok).unwrap();
            out.flush().unwrap();
            tok = l.next_token();
        }
    }
}
<commit_msg>Correct REPL behaviour.<commit_after>use std::io::Stdin;
use std::io::Stdout;
use std::io::Write;

use super::lexer::Lexer;
use super::token::TokenType;

const PROMPT: &'static str = ">> ";

pub fn start(mut in_: Stdin, mut out: Stdout) {
    loop {
        print!("{}", PROMPT);
        out.flush().unwrap();

        let mut s = String::new();
        in_.read_line(&mut s).expect("Did not enter a correct string");

        let mut l = Lexer::new(s);
        let mut tok = l.next_token();
        while tok.token_type != TokenType::EOF {
            write!(&mut out, "{:?}\n", tok).unwrap();
            out.flush().unwrap();
            tok = l.next_token();
        }
    }
}
<|endoftext|>