<commit_before>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

#[link(name = "str2", author = "kcantu", vers = "0.0")];
use std;

// a better slice, unicode safe
// since strings are null terminated, cannot copy in place
//
// start is the character position to begin copying
// end is the character position which should not be copied
//
// Does not make internal conversion to char (which is UTF-32/UCS-4),
// but is UTF-8 aware.
//

// helper: note, slice_chars could be faster (by not starting byte_position from zero the second time)
// if this was a named block internal to slice_chars
fn byte_position (&&ss: str, char_position: uint) -> uint
{
   let cursor_char = 0u;
   let cursor_byte = 0u;

   while cursor_char < char_position {
      let sz = str::utf8_char_width(ss[cursor_byte]);
      assert sz > 0u;
      cursor_byte += sz;
      cursor_char += 1u;
   }
   assert cursor_char <= str::char_len(ss);
   ret cursor_char;
}

fn slice_chars(ss: str, begin: uint, end: uint) -> str unsafe
{
   assert begin <= end;
   assert end <= str::char_len(ss);

   // find the begin and end
   let byte_begin = byte_position(ss, begin);
   let byte_end   = byte_position(ss, end);

   // copy the bytes
   let new_vector = [];
   let ii = byte_begin;

   while ii < byte_end {
      vec::push(new_vector, ss[ii]);
      ii += 1u;
   }
   vec::push(new_vector, 0u8);

   // return as a string
   let new_string: str = unsafe::reinterpret_cast(new_vector);
   unsafe::leak(new_vector);
   ret new_string;
}

#[test]
fn test_slice() {
    assert (str::eq("ab", slice_chars("abc", 0u, 2u)));
    assert (str::eq("bc", slice_chars("abc", 1u, 3u)));
    assert (str::eq("", slice_chars("abc", 1u, 1u)));
    fn a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaaaaaaa"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaa"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_a(),
                    slice_chars(a_million_letter_a(), 0u, 500000u)));
}

// a more general split, unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: fn&(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a ()
{
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example ()
{
   let s = "中华Việt Nam";
   let i = 0u;
   while i < str::byte_len(s)
   {
      let {ch:c, next:j} = str::char_range_at(s, i);
      std::io::println(#fmt("%u: %c",i,c));
      i = j;
   }

   /* Output:
      0: 中
      3: 华
      6: V
      7: i
      8: ệ
      11: t
      12:
      13: N
      14: a
      15: m
   */
}

<commit_msg>a test that does not work, aha!<commit_after>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

#[link(name = "str2", author = "kcantu", vers = "0.0")];
use std;

// a better slice, unicode safe
// since strings are null terminated, cannot copy in place
//
// start is the character position to begin copying
// end is the character position which should not be copied
//
// Does not make internal conversion to char (which is UTF-32/UCS-4),
// but is UTF-8 aware.
//

// helper: note, slice_chars could be faster (by not starting byte_position from zero the second time)
// if this was a named block internal to slice_chars
fn byte_position (&&ss: str, char_position: uint) -> uint
{
   let cursor_char = 0u;
   let cursor_byte = 0u;

   while cursor_char < char_position {
      let sz = str::utf8_char_width(ss[cursor_byte]);
      assert sz > 0u;
      cursor_byte += sz;
      cursor_char += 1u;
   }
   assert cursor_char <= str::char_len(ss);
   ret cursor_char;
}

fn slice_chars(ss: str, begin: uint, end: uint) -> str unsafe
{
   assert begin <= end;
   assert end <= str::char_len(ss);

   // find the begin and end
   let byte_begin = byte_position(ss, begin);
   let byte_end   = byte_position(ss, end);

   // copy the bytes
   let new_vector = [];
   let ii = byte_begin;

   while ii < byte_end {
      vec::push(new_vector, ss[ii]);
      ii += 1u;
   }
   vec::push(new_vector, 0u8);

   // return as a string
   let new_string: str = unsafe::reinterpret_cast(new_vector);
   unsafe::leak(new_vector);
   ret new_string;
}

#[test]
fn test_slice() {
    assert (str::eq("ab", slice_chars("abc", 0u, 2u)));
    assert (str::eq("bc", slice_chars("abc", 1u, 3u)));
    assert (str::eq("", slice_chars("abc", 1u, 1u)));
    fn a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaaaaaaa"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_a() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "aaaaa"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_a(),
                    slice_chars(a_million_letter_a(), 0u, 500000u)));
}

#[test]
fn test_slice_with_unicode() {
    fn a_million_letter_华() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "华华华华华华华华华华"; i += 1; }
        ret rs;
    }
    fn half_a_million_letter_华() -> str {
        let i = 0;
        let rs = "";
        while i < 100000 { rs += "华华华华华"; i += 1; }
        ret rs;
    }
    assert (str::eq(half_a_million_letter_华(),
                    slice_chars(a_million_letter_华(), 0u, 500000u)));
}

#[test]
fn equals_unicode() {
   let data = "ประเทศไทย中华Việt Nam";
   let data2 = "ประเทศไทย中华Việt Nam";
   assert str::eq(data,data2);

   assert str::eq("华", "华");
   assert str::eq("华华", "华华");
}

// a more general split, unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: fn&(cc: char)->bool) -> [str]
{
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a ()
{
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str]
{
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str]
{
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn ()
{
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example ()
{
   let s = "中华Việt Nam";
   let i = 0u;
   while i < str::byte_len(s)
   {
      let {ch:c, next:j} = str::char_range_at(s, i);
      std::io::println(#fmt("%u: %c",i,c));
      i = j;
   }

   /* Output:
      0: 中
      3: 华
      6: V
      7: i
      8: ệ
      11: t
      12:
      13: N
      14: a
      15: m
   */
}

<|endoftext|>


<commit_before>use lucet_module::bindings::Bindings;
use std::collections::HashMap;
use std::path::PathBuf;

fn test_file(f: &str) -> PathBuf {
    PathBuf::from(format!("tests/bindings/{}", f))
}

#[test]
fn explicit() {
    let mut explicit_map = HashMap::new();
    explicit_map.insert(String::from("hello"), String::from("goodbye"));
    let map = Bindings::env(explicit_map);

    let result = map.translate("env", "hello").unwrap();
    assert!(result == "goodbye");

    let result = map.translate("env", "nonexistent");
    if let Ok(_) = result {
        assert!(
            false,
            "explicit import map returned value for non-existent symbol"
        )
    }
}

#[test]
fn explicit_from_nonexistent_file() {
    let fail_map = Bindings::from_file(&test_file("nonexistent_bindings.json"));
    assert!(
        fail_map.is_err(),
        "ImportMap::explicit_from_file did not fail on a non-existent file"
    );
}

#[test]
fn explicit_from_garbage_file() {
    let fail_map = Bindings::from_file(&test_file("garbage.json"));
    assert!(
        fail_map.is_err(),
        "ImportMap::explicit_from_file did not fail on a garbage file"
    );
}

#[test]
fn explicit_from_file() {
    let map = Bindings::from_file(&test_file("bindings_test.json"))
        .expect("load valid bindings from file");
    let result = map.translate("env", "hello").expect("hello has a binding");
    assert!(result == "json is cool");

    assert!(
        map.translate("env", "nonexistent").is_err(),
        "bindings from file returned value for non-existent symbol"
    );
}
<commit_msg>fix test assertion<commit_after>use lucet_module::bindings::Bindings;
use std::collections::HashMap;
use std::path::PathBuf;

fn test_file(f: &str) -> PathBuf {
    PathBuf::from(format!("tests/bindings/{}", f))
}

#[test]
fn explicit() {
    let mut explicit_map = HashMap::new();
    explicit_map.insert(String::from("hello"), String::from("goodbye"));
    let map = Bindings::env(explicit_map);

    let result = map.translate("env", "hello").unwrap();
    assert!(result == "goodbye");

    let result = map.translate("env", "nonexistent");
    assert!(
        result.is_err(),
        "explicit import map returned value for non-existent symbol"
    );
}

#[test]
fn explicit_from_nonexistent_file() {
    let fail_map = Bindings::from_file(&test_file("nonexistent_bindings.json"));
    assert!(
        fail_map.is_err(),
        "ImportMap::explicit_from_file did not fail on a non-existent file"
    );
}

#[test]
fn explicit_from_garbage_file() {
    let fail_map = Bindings::from_file(&test_file("garbage.json"));
    assert!(
        fail_map.is_err(),
        "ImportMap::explicit_from_file did not fail on a garbage file"
    );
}

#[test]
fn explicit_from_file() {
    let map = Bindings::from_file(&test_file("bindings_test.json"))
        .expect("load valid bindings from file");
    let result = map.translate("env", "hello").expect("hello has a binding");
    assert!(result == "json is cool");

    assert!(
        map.translate("env", "nonexistent").is_err(),
        "bindings from file returned value for non-existent symbol"
    );
}
<|endoftext|>


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

use docopt::Docopt;
use lalrpop::Configuration;
use std::env;
use std::io::{self, Write};
use std::process;

fn main() {
    main1().unwrap();
}

fn main1() -> io::Result<()> {
    let mut stderr = std::io::stderr();

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

    let mut config = Configuration::new();

    match args.flag_level.unwrap_or(LevelFlag::Info) {
        LevelFlag::Quiet => config.log_quiet(),
        LevelFlag::Info => config.log_info(),
        LevelFlag::Verbose => config.log_verbose(),
        LevelFlag::Debug => config.log_debug(),
    };

    if args.flag_force {
        config.force_build(true);
    }

    if args.flag_color {
        config.always_use_colors();
    }

    if args.flag_comments {
        config.emit_comments(true);
    }

    if args.flag_report {
        config.emit_report(true);
    }

    if args.arg_inputs.len() == 0 {
        try!(writeln!(stderr, "Error: no input files specified! Try --help for help."));
        process::exit(1);
    }

    for arg in args.arg_inputs {
        match config.process_file(&arg) {
            Ok(()) => { }
            Err(err) => {
                try!(writeln!(stderr, "Error encountered processing `{}`: {}",
                              arg, err));
                process::exit(1);
            }
        }
    }

    Ok(())
}

const USAGE: &'static str = "
Usage: lalrpop [options] <inputs>...
       lalrpop --help

Options:
    -l, --level LEVEL    Set the debug level. (Default: info)
                         Valid values: quiet, info, verbose, debug.
    -f, --force          Force execution, even if the .lalrpop file is older than the .rs file.
    -c, --color          Force colorful output, even if this is not a TTY.
    --comments           Enable comments in the generated code.
    --report             Generate report files.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_inputs: Vec<String>,
    flag_level: Option<LevelFlag>,
    flag_force: bool,
    flag_color: bool,
    flag_comments: bool,
    flag_report: bool
}

#[derive(Debug, RustcDecodable)]
enum LevelFlag {
    Quiet, Info, Verbose, Debug
}

#[cfg(test)]
mod test {
    use docopt::Docopt;
    use super::USAGE;
    use super::Args;

    #[test]
    fn test_usage_help() {
        let argv = || vec!["lalrpop", "--help"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.help(false).argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_single_input() {
        let argv = || vec!["lalrpop", "file.lalrpop"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_multiple_inputs() {
        let argv = || vec!["lalrpop", "file.lalrpop", "../file2.lalrpop"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }
}
<commit_msg>added version information https://github.com/nikomatsakis/lalrpop/issues/224<commit_after>extern crate docopt;
extern crate lalrpop;
extern crate rustc_serialize;

use docopt::Docopt;
use lalrpop::Configuration;
use std::env;
use std::io::{self, Write};
use std::process;

static VERSION: &'static str = env!("CARGO_PKG_VERSION");

fn main() {
    main1().unwrap();
}

fn main1() -> io::Result<()> {
    let mut stderr = std::io::stderr();
    let mut stdout = std::io::stdout();

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

    if args.flag_version {
        try!(writeln!(stdout, "{}", VERSION));
        process::exit(0);
    }

    let mut config = Configuration::new();

    match args.flag_level.unwrap_or(LevelFlag::Info) {
        LevelFlag::Quiet => config.log_quiet(),
        LevelFlag::Info => config.log_info(),
        LevelFlag::Verbose => config.log_verbose(),
        LevelFlag::Debug => config.log_debug(),
    };

    if args.flag_force {
        config.force_build(true);
    }

    if args.flag_color {
        config.always_use_colors();
    }

    if args.flag_comments {
        config.emit_comments(true);
    }

    if args.flag_report {
        config.emit_report(true);
    }

    if args.arg_inputs.len() == 0 {
        try!(writeln!(stderr, "Error: no input files specified! Try --help for help."));
        process::exit(1);
    }

    for arg in args.arg_inputs {
        match config.process_file(&arg) {
            Ok(()) => { }
            Err(err) => {
                try!(writeln!(stderr, "Error encountered processing `{}`: {}",
                              arg, err));
                process::exit(1);
            }
        }
    }

    Ok(())
}

const USAGE: &'static str = "
Usage: lalrpop [options] <inputs>...
       lalrpop --help
       lalrpop (-V | --version)

Options:
    -V, --version        Print version.
    -l, --level LEVEL    Set the debug level. (Default: info)
                         Valid values: quiet, info, verbose, debug.
    -f, --force          Force execution, even if the .lalrpop file is older than the .rs file.
    -c, --color          Force colorful output, even if this is not a TTY.
    --comments           Enable comments in the generated code.
    --report             Generate report files.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_inputs: Vec<String>,
    flag_level: Option<LevelFlag>,
    flag_force: bool,
    flag_color: bool,
    flag_comments: bool,
    flag_report: bool,
    flag_version: bool,
}

#[derive(Debug, RustcDecodable)]
enum LevelFlag {
    Quiet, Info, Verbose, Debug
}

#[cfg(test)]
mod test {
    use docopt::Docopt;
    use super::USAGE;
    use super::Args;

    #[test]
    fn test_usage_help() {
        let argv = || vec!["lalrpop", "--help"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.help(false).argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_version() {
        let argv = || vec!["lalrpop", "--version"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_single_input() {
        let argv = || vec!["lalrpop", "file.lalrpop"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }

    #[test]
    fn test_usage_multiple_inputs() {
        let argv = || vec!["lalrpop", "file.lalrpop", "../file2.lalrpop"];
        let _: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(argv().into_iter()).decode())
            .unwrap();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate schemamama;
extern crate schemamama_postgres;
extern crate postgres;
mod schema;

#[macro_use]
extern crate log;
extern crate log4rs;

extern crate iron;
extern crate router;
extern crate logger;

use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::status;
use logger::Logger;
use router::Router;

use std::env;
use std::io::Read;
use std::ops::Deref;

extern crate hyper;
extern crate url;
use url::Url;

extern crate uuid;
use uuid::Uuid;
extern crate serde;
extern crate serde_json;
use serde_json::{Map, Value};

extern crate r2d2;
extern crate r2d2_postgres;
extern crate persistent;
use persistent::Read as PRead;
use persistent::State;
use postgres::error::SqlState;
use postgres::rows::{Row, RowIndex};
use postgres::types::FromSql;

#[macro_use]
extern crate potboiler_common;
use potboiler_common::db;
use potboiler_common::server_id;

use std::error::Error;
use std::fmt::{self, Debug};

include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

mod notifications;

#[derive(Debug)]
struct StringError(String);

impl Error for StringError {
    fn description(&self) -> &str {
        &*self.0
    }
}

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

fn log_status<T: Into<String>>(req: &mut Request, stmt: T) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare(&stmt.into()).expect("prepare failure");
    let mut logs = Map::new();
    for row in &stmt.query(&[]).expect("last select works") {
        let id: Uuid = row.get("id");
        let owner: Uuid = row.get("owner");
        logs.insert(owner.to_string(), serde_json::to_value(&id.to_string()));
    }
    let value = Value::Object(logs);
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&value).unwrap())))
}

fn log_lasts(req: &mut Request) -> IronResult<Response> {
    log_status(req, "SELECT id, owner from log WHERE next is null")
}

fn log_firsts(req: &mut Request) -> IronResult<Response> {
    log_status(req, "SELECT id, owner from log WHERE prev is null")
}

fn new_log(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    let id = Uuid::new_v4();
    let hyphenated = id.hyphenated().to_string();
    let server_id = get_server_id!(&req).deref();
    let stmt = conn.prepare("SELECT id from log WHERE next is null and owner = $1 LIMIT 1")
        .expect("prepare failure");
    let results = stmt.query(&[server_id]).expect("last select works");
    let previous = if results.is_empty() {
        None
    } else {
        let row = results.get(0);
        let id: Uuid = row.get("id");
        Some(id)
    };
    conn.execute("UPDATE log set next = $1 where owner = $2 and next is null",
                 &[&id, server_id])
        .expect("update worked");
    conn.execute("INSERT INTO log (id, owner, data, prev) VALUES ($1, $2, $3, $4)",
                 &[&id, server_id, &json, &previous])
        .expect("insert worked");
    let notifications = notifications::get_notifications_list(req);
    let client = hyper::client::Client::new();
    for notifier in notifications {
        let mut map: serde_json::Map<String, String> = serde_json::Map::new();
        map.insert("url".to_string(),
                   "http://localhost:8001/kv/event".to_string());
        debug!("Notifying {:?}", notifier);
        let res = client.post(&notifier)
            .body(&serde_json::ser::to_string(&map).unwrap())
            .send()
            .unwrap();
        if res.status != hyper::status::StatusCode::NoContent {
            warn!("Failed to notify {:?}: {:?}", &notifier, res.status);
        }
    }
    let new_url = {
        let req_url = req.url.clone();
        let base_url = req_url.into_generic_url();
        base_url.join(&format!("/log/{}", &hyphenated)).expect("join url works")
    };
    Ok(Response::with((status::Created,
                       Redirect(iron::Url::from_generic_url(new_url).expect("URL parsed ok")))))
}

fn get_with_null<I, T>(row: &Row, index: I) -> Option<T>
    where I: RowIndex,
          T: FromSql
{
    match row.get_opt(index) {
        Some(val) => {
            match val {
                Ok(val) => Some(val),
                Err(_) => None,
            }
        }
        None => None,
    }
}

fn get_log(req: &mut Request) -> IronResult<Response> {
    let ref query = req.extensions
        .get::<Router>()
        .unwrap()
        .find("entry_id")
        .unwrap_or("/");
    let query_id = match Uuid::parse_str(&query) {
        Ok(val) => val,
        Err(_) => {
            return Ok(Response::with((status::NotFound, format!("No log {}", query))));
        }
    };
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("SELECT owner, next, prev, data from log where id=$1").expect("prepare failure");
    let results = stmt.query(&[&query_id]).expect("bad query");
    if results.is_empty() {
        Ok(Response::with((status::NotFound, format!("No log {}", query))))
    } else {
        let row = results.get(0);
        let log = Log {
            id: query_id,
            owner: row.get("owner"),
            prev: get_with_null(&row, "prev"),
            next: get_with_null(&row, "next"),
            data: row.get("data")
        };
        Ok(Response::with((status::Ok, serde_json::to_string(&log).unwrap())))
    }
}

fn url_from_body(req: &mut Request) -> Result<Option<String>, IronError> {
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    Ok(Some(format!("{:?}",json.find("url").unwrap())))
}

fn log_register(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute("INSERT INTO notifications (url) VALUES ($1)", &[&url]) {
                Ok(_) => {
                    notifications::insert_notifier(req, &url);
                    Ok(Response::with((status::NoContent)))
                }
                Err(err) => {
                    if let postgres::error::Error::Db(dberr) = err {
                        match dberr.code {
                            SqlState::UniqueViolation => Ok(Response::with((status::NoContent))),
                            _ => Err(IronError::new(dberr, (status::BadRequest, "Some other error"))),
                        }
                    } else {
                        Err(IronError::new(err, (status::BadRequest, "Some other error")))
                    }
                }
            }
        }
    }
}

fn log_deregister(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    conn.execute("DELETE from notifications where url = $1",
                 &[&url_from_body(req).unwrap().unwrap()])
        .expect("delete worked");
    Ok(Response::with((status::NoContent)))
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).unwrap();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    schema::up(&conn).unwrap();
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = Router::new();
    router.get("/log", log_lasts);
    router.post("/log", new_log);
    router.get("/log/first", log_firsts);
    router.get("/log/:entry_id", get_log);
    router.post("/log/register", log_register);
    router.post("/log/deregister", log_deregister);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    let mut notifiers = Vec::new();
    let stmt = conn.prepare("select url from notifications").expect("prepare failure");
    for row in &stmt.query(&[]).expect("notifications select works") {
        let url: String = row.get("url");
        notifiers.push(url);
    }
    chain.link_before(State::<notifications::Notifications>::one(notifiers));
    chain.link_before(PRead::<server_id::ServerId>::one(server_id::setup()));
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Potboiler booted");
    Iron::new(chain).http("localhost:8000").unwrap();
}
<commit_msg>Output event to notifiers<commit_after>#[macro_use]
extern crate schemamama;
extern crate schemamama_postgres;
extern crate postgres;
mod schema;

#[macro_use]
extern crate log;
extern crate log4rs;

extern crate iron;
extern crate router;
extern crate logger;

use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::status;
use logger::Logger;
use router::Router;

use std::env;
use std::io::Read;
use std::ops::Deref;

extern crate hyper;
extern crate url;
use url::Url;

extern crate uuid;
use uuid::Uuid;
extern crate serde;
extern crate serde_json;
use serde_json::{Map, Value};

extern crate r2d2;
extern crate r2d2_postgres;
extern crate persistent;
use persistent::Read as PRead;
use persistent::State;
use postgres::error::SqlState;
use postgres::rows::{Row, RowIndex};
use postgres::types::FromSql;

#[macro_use]
extern crate potboiler_common;
use potboiler_common::db;
use potboiler_common::server_id;

use std::error::Error;
use std::fmt::{self, Debug};

include!(concat!(env!("OUT_DIR"), "/serde_types.rs"));

mod notifications;

#[derive(Debug)]
struct StringError(String);

impl Error for StringError {
    fn description(&self) -> &str {
        &*self.0
    }
}

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

fn log_status<T: Into<String>>(req: &mut Request, stmt: T) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare(&stmt.into()).expect("prepare failure");
    let mut logs = Map::new();
    for row in &stmt.query(&[]).expect("last select works") {
        let id: Uuid = row.get("id");
        let owner: Uuid = row.get("owner");
        logs.insert(owner.to_string(), serde_json::to_value(&id.to_string()));
    }
    let value = Value::Object(logs);
    Ok(Response::with((status::Ok, serde_json::ser::to_string(&value).unwrap())))
}

fn log_lasts(req: &mut Request) -> IronResult<Response> {
    log_status(req, "SELECT id, owner from log WHERE next is null")
}

fn log_firsts(req: &mut Request) -> IronResult<Response> {
    log_status(req, "SELECT id, owner from log WHERE prev is null")
}

fn new_log(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    let id = Uuid::new_v4();
    let hyphenated = id.hyphenated().to_string();
    let server_id = get_server_id!(&req).deref();
    let stmt = conn.prepare("SELECT id from log WHERE next is null and owner = $1 LIMIT 1")
        .expect("prepare failure");
    let results = stmt.query(&[server_id]).expect("last select works");
    let previous = if results.is_empty() {
        None
    } else {
        let row = results.get(0);
        let id: Uuid = row.get("id");
        Some(id)
    };
    conn.execute("UPDATE log set next = $1 where owner = $2 and next is null",
                 &[&id, server_id])
        .expect("update worked");
    conn.execute("INSERT INTO log (id, owner, data, prev) VALUES ($1, $2, $3, $4)",
                 &[&id, server_id, &json, &previous])
        .expect("insert worked");
    let notifications = notifications::get_notifications_list(req);
    let client = hyper::client::Client::new();
    for notifier in notifications {
        let log = Log {
            id: id,
            owner: server_id.clone(),
            prev: previous,
            next: None,
            data: json.clone(),
        };
        debug!("Notifying {:?}", notifier);
        let res = client.post(&notifier)
            .body(&serde_json::ser::to_string(&log).unwrap())
            .send()
            .unwrap();
        if res.status != hyper::status::StatusCode::NoContent {
            warn!("Failed to notify {:?}: {:?}", &notifier, res.status);
        }
    }
    let new_url = {
        let req_url = req.url.clone();
        let base_url = req_url.into_generic_url();
        base_url.join(&format!("/log/{}", &hyphenated)).expect("join url works")
    };
    Ok(Response::with((status::Created,
                       Redirect(iron::Url::from_generic_url(new_url).expect("URL parsed ok")))))
}

fn get_with_null<I, T>(row: &Row, index: I) -> Option<T>
    where I: RowIndex,
          T: FromSql
{
    match row.get_opt(index) {
        Some(val) => {
            match val {
                Ok(val) => Some(val),
                Err(_) => None,
            }
        }
        None => None,
    }
}

fn get_log(req: &mut Request) -> IronResult<Response> {
    let ref query = req.extensions
        .get::<Router>()
        .unwrap()
        .find("entry_id")
        .unwrap_or("/");
    let query_id = match Uuid::parse_str(&query) {
        Ok(val) => val,
        Err(_) => {
            return Ok(Response::with((status::NotFound, format!("No log {}", query))));
        }
    };
    let conn = get_pg_connection!(&req);
    let stmt = conn.prepare("SELECT owner, next, prev, data from log where id=$1").expect("prepare failure");
    let results = stmt.query(&[&query_id]).expect("bad query");
    if results.is_empty() {
        Ok(Response::with((status::NotFound, format!("No log {}", query))))
    } else {
        let row = results.get(0);
        let log = Log {
            id: query_id,
            owner: row.get("owner"),
            prev: get_with_null(&row, "prev"),
            next: get_with_null(&row, "next"),
            data: row.get("data"),
        };
        Ok(Response::with((status::Ok, serde_json::to_string(&log).unwrap())))
    }
}

fn url_from_body(req: &mut Request) -> Result<Option<String>, IronError> {
    let body_string = {
        let mut body = String::new();
        req.body.read_to_string(&mut body).expect("could read from body");
        body
    };
    let json: Value = match serde_json::de::from_str(&body_string) {
        Ok(val) => val,
        Err(err) => return Err(IronError::new(err, (status::BadRequest, "Bad JSON"))),
    };
    Ok(Some(json.find("url").unwrap().as_str().unwrap().to_string()))
}

fn log_register(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering {:?}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute("INSERT INTO notifications (url) VALUES ($1)", &[&url]) {
                Ok(_) => {
                    notifications::insert_notifier(req, &url);
                    Ok(Response::with((status::NoContent)))
                }
                Err(err) => {
                    if let postgres::error::Error::Db(dberr) = err {
                        match dberr.code {
                            SqlState::UniqueViolation => Ok(Response::with((status::NoContent))),
                            _ => Err(IronError::new(dberr, (status::BadRequest, "Some other error"))),
                        }
                    } else {
                        Err(IronError::new(err, (status::BadRequest, "Some other error")))
                    }
                }
            }
        }
    }
}

fn log_deregister(req: &mut Request) -> IronResult<Response> {
    let conn = get_pg_connection!(&req);
    conn.execute("DELETE from notifications where url = $1",
                 &[&url_from_body(req).unwrap().unwrap()])
        .expect("delete worked");
    Ok(Response::with((status::NoContent)))
}

fn main() {
    log4rs::init_file("log.yaml", Default::default()).unwrap();
    let db_url: &str = &env::var("DATABASE_URL").expect("Needed DATABASE_URL");
    let pool = db::get_pool(db_url);
    let conn = pool.get().unwrap();
    schema::up(&conn).unwrap();
    let (logger_before, logger_after) = Logger::new(None);
    let mut router = Router::new();
    router.get("/log", log_lasts);
    router.post("/log", new_log);
    router.get("/log/first", log_firsts);
    router.get("/log/:entry_id", get_log);
    router.post("/log/register", log_register);
    router.post("/log/deregister", log_deregister);
    let mut chain = Chain::new(router);
    chain.link_before(logger_before);
    chain.link_after(logger_after);
    let mut notifiers = Vec::new();
    let stmt = conn.prepare("select url from notifications").expect("prepare failure");
    for row in &stmt.query(&[]).expect("notifications select works") {
        let url: String = row.get("url");
        notifiers.push(url);
    }
    chain.link_before(State::<notifications::Notifications>::one(notifiers));
    chain.link_before(PRead::<server_id::ServerId>::one(server_id::setup()));
    chain.link(PRead::<db::PostgresDB>::both(pool));
    info!("Potboiler booted");
    Iron::new(chain).http("localhost:8000").unwrap();
}
<|endoftext|>


<commit_before>use ast::{Node, Index, Ident, OperatorKind, VariableDeclarationKind};

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Value<'src> {
    Undefined,
    Null,
    True,
    False,
    Number(&'src str),
    Binary(u64),
    String(&'src str),
    RawQuasi(&'src str),
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Item<'src> {
    // Identifiers
    Identifier(Ident<'src>),
    This,

    // Expressions
    ValueExpr(Value<'src>),
    ArrayExpr(Index),
    SequenceExpr(Index),
    MemberExpr {
        object: Index,
        property: Index,
    },
    CallExpr {
        callee: Index,
        arguments: Option<Index>,
    },
    BinaryExpr {
        parenthesized: bool,
        operator: OperatorKind,
        left: Index,
        right: Index,
    },
    Prefix {
        operator: OperatorKind,
        operand: Index,
    },
    PostfixExpr {
        operator: OperatorKind,
        operand: Index,
    },
    ConditionalExpr {
        test: Index,
        consequent: Index,
        alternate: Index,
    },
    ArrowExpr {
        params: Option<Index>,
        body: Option<Index>,
    },
    FunctionExpr {
        name: Option<Ident<'src>>,
        params: Option<Index>,
        body: Option<Index>,
    },
    ObjectExpr {
        body: Option<Index>,
    },
    ClassExpr {
        name: Option<Ident<'src>>,
        extends: Option<Ident<'src>>,
        body: Option<Index>,
    },

    // Object
    ShorthandMember(Ident<'src>),
    ObjectMember {
        key: Ident<'src>,
        value: Index,
    },
    ComputedMember {
        key: Index,
        value: Index,
    },

    // Declaration
    VariableDeclarator {
        name: Index,
        value: Option<Index>,
    },

    // Statements
    EmptyStatement,
    ExpressionStatement(Index),
    DeclarationStatemenet {
        kind: VariableDeclarationKind,
        declarators: Index,
    },
    FunctionStatement {
        name: Ident<'src>,
        params: Option<Index>,
        body: Option<Index>,
    },
    ReturnStatement {
        value: Option<Index>,
    }

}

impl<'src> Item<'src> {
    #[inline]
    pub fn at(self, start: usize, end: usize) -> Node<'src> {
        Node::new(start, end, self)
    }
}
<commit_msg>Adding additional items<commit_after>use ast::{Node, Index, Ident, OperatorKind, VariableDeclarationKind};

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Value<'src> {
    Undefined,
    Null,
    True,
    False,
    Number(&'src str),
    Binary(u64),
    String(&'src str),
    RawQuasi(&'src str),
    RegEx {
         pattern: &'src str,
         flags: &'src str
    },
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Item<'src> {
    // Identifiers
    Identifier(Ident<'src>),
    This,

    // Expressions
    ValueExpr(Value<'src>),
    ArrayExpr(Index),
    SequenceExpr(Index),
    MemberExpr {
        object: Index,
        property: Index,
    },
    CallExpr {
        callee: Index,
        arguments: Option<Index>,
    },
    BinaryExpr {
        parenthesized: bool,
        operator: OperatorKind,
        left: Index,
        right: Index,
    },
    Prefix {
        operator: OperatorKind,
        operand: Index,
    },
    PostfixExpr {
        operator: OperatorKind,
        operand: Index,
    },
    ConditionalExpr {
        test: Index,
        consequent: Index,
        alternate: Index,
    },
    ArrowExpr {
        params: Option<Index>,
        body: Option<Index>,
    },
    FunctionExpr {
        name: Option<Ident<'src>>,
        params: Option<Index>,
        body: Option<Index>,
    },
    ObjectExpr {
        body: Option<Index>,
    },
    ClassExpr {
        name: Option<Ident<'src>>,
        extends: Option<Ident<'src>>,
        body: Option<Index>,
    },

    // Object
    ShorthandMember(Ident<'src>),
    ObjectMember {
        key: Ident<'src>,
        value: Index,
    },
    ComputedMember {
        key: Index,
        value: Index,
    },

    // Declaration
    VariableDeclarator {
        name: Index,
        value: Option<Index>,
    },

    // Statements
    EmptyStatement,
    ExpressionStatement(Index),
    DeclarationStatemenet {
        kind: VariableDeclarationKind,
        declarators: Index,
    },
    FunctionStatement {
        name: Ident<'src>,
        params: Option<Index>,
        body: Option<Index>,
    },
    ReturnStatement {
        value: Option<Index>,
    },
    BreakStatement {
        label: Option<Index>,
    },
    IfStatement {
        test: Index,
        consequent: Index,
        alternate: Option<Index>
    },
    WhileStatement {
        test: Index,
        body: Index,
    },
    DoStatement {
        test: Index,
        body: Index,
    },
    ForStatement {
        init: Option<Index>,
        test: Option<Index>,
        update: Option<Index>,
        body: Index
    },
    ForIn {
        left: Index,
        right: Index,
        body: Index
    },
    ForOf {
        left: Index,
        right: Index,
        body: Index
    },
    ThrowStatement {
        value: Index
    },
    TryStatement {
        body: Index,
        error: Ident<'src>,
        handler: Index
    }

}

impl<'src> Item<'src> {
    #[inline]
    pub fn at(self, start: usize, end: usize) -> Node<'src> {
        Node::new(start, end, self)
    }
}
<|endoftext|>


<commit_before>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath;
use cgmath::{Deg, Point2};
use character::{CharacterDrawable, controls::CharacterInputState};
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{camera::CameraInputState, can_move_to_tile, Dimensions, direction, direction_movement, get_orientation, load_texture, orientation::{Orientation, Stance}, overlaps};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};
use terrain::path_finding::calc_route;
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
  is_colliding: bool,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = Dimensions::get_view_matrix();

    ZombieDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(Deg(60.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position,
      previous_position: Position::new([0.0, 0.0]),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
      is_colliding: false,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, character: &CharacterDrawable) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]
      ]);

    self.previous_position = Position::new([
      ci.x_movement,
      ci.y_movement
    ]);
    let movement_speed = 1.4;

    let is_dead = self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath;
    if is_dead {
      let dir = direction(
        Point2::new(self.position.position[0], self.position.position[1]),
        Point2::new(character.position.position[0], character.position.position[1])
      );

      calc_route(self.position, character.position);

      self.direction = get_orientation(dir);

      self.movement_direction = direction_movement(dir);
      self.stance = Stance::Walking;
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    let new_pos = Position::new([
      self.position.position[0] + offset_delta.position[0] + (self.movement_direction.x * movement_speed),
      self.position.position[1] + offset_delta.position[1] + (self.movement_direction.y * movement_speed)
    ]);

    let new_pos_without_movement = Position::new([
      self.position.position[0] + offset_delta.position[0],
      self.position.position[1] + offset_delta.position[1]
    ]);

    let tile_pos = Position::new([ci.x_movement - new_pos.position[0], ci.y_movement - new_pos.position[1]]);

    if can_move_to_tile(tile_pos) {
      self.position = new_pos;
    } else {
      self.position = new_pos_without_movement;
    }
  }

  pub fn check_bullet_hits(&mut self, bullets: &[BulletDrawable]) {
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 20.0, 40.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: [VertexData; 4] = [
      VertexData::new([-25.0, -35.0], [0.0, 1.0]),
      VertexData::new([25.0, -35.0], [1.0, 1.0]),
      VertexData::new([25.0, 35.0], [1.0, 0.0]),
      VertexData::new([-25.0, 35.0], [0.0, 0.0]),
    ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes);
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, CharacterDrawable>,
                     ReadStorage<'a, Bullets>,
                     Read<'a, Dimensions>);

  fn run(&mut self, (mut zombies, camera_input, character_input, character, bullets, dim): Self::SystemData) {
    use specs::join::Join;

    for (zs, camera, ci, c, bs) in (&mut zombies, &camera_input, &character_input, &character, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, c);
        z.check_bullet_hits(&bs.bullets);
      }
    }
  }
}
<commit_msg>Rename variable<commit_after>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath;
use cgmath::{Deg, Point2};
use character::{CharacterDrawable, controls::CharacterInputState};
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{camera::CameraInputState, can_move_to_tile, Dimensions, direction, direction_movement, get_orientation, load_texture, orientation::{Orientation, Stance}, overlaps};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};
use terrain::path_finding::calc_route;
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
  is_colliding: bool,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = Dimensions::get_view_matrix();

    ZombieDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(Deg(60.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position,
      previous_position: Position::new([0.0, 0.0]),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
      is_colliding: false,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, character: &CharacterDrawable) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]
      ]);

    self.previous_position = Position::new([
      ci.x_movement,
      ci.y_movement
    ]);
    let movement_speed = 1.4;

    let is_alive = self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath;
    if is_alive {
      let dir = direction(
        Point2::new(self.position.position[0], self.position.position[1]),
        Point2::new(character.position.position[0], character.position.position[1])
      );

      calc_route(self.position, character.position);

      self.direction = get_orientation(dir);

      self.movement_direction = direction_movement(dir);
      self.stance = Stance::Walking;
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    let new_pos = Position::new([
      self.position.position[0] + offset_delta.position[0] + (self.movement_direction.x * movement_speed),
      self.position.position[1] + offset_delta.position[1] + (self.movement_direction.y * movement_speed)
    ]);

    let new_pos_without_movement = Position::new([
      self.position.position[0] + offset_delta.position[0],
      self.position.position[1] + offset_delta.position[1]
    ]);

    let tile_pos = Position::new([ci.x_movement - new_pos.position[0], ci.y_movement - new_pos.position[1]]);

    if can_move_to_tile(tile_pos) {
      self.position = new_pos;
    } else {
      self.position = new_pos_without_movement;
    }
  }

  pub fn check_bullet_hits(&mut self, bullets: &[BulletDrawable]) {
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 20.0, 40.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: [VertexData; 4] = [
      VertexData::new([-25.0, -35.0], [0.0, 1.0]),
      VertexData::new([25.0, -35.0], [1.0, 1.0]),
      VertexData::new([25.0, 35.0], [1.0, 0.0]),
      VertexData::new([-25.0, 35.0], [0.0, 0.0]),
    ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes);
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, CharacterDrawable>,
                     ReadStorage<'a, Bullets>,
                     Read<'a, Dimensions>);

  fn run(&mut self, (mut zombies, camera_input, character_input, character, bullets, dim): Self::SystemData) {
    use specs::join::Join;

    for (zs, camera, ci, c, bs) in (&mut zombies, &camera_input, &character_input, &character, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, c);
        z.check_bullet_hits(&bs.bullets);
      }
    }
  }
}
<|endoftext|>


<commit_before>import stb_image::*;
import stb_image::bindgen::*;
import libc::types::os::arch::c95::c_int;
import ptr::{addr_of, is_null};
import str::as_c_str;
import vec::as_buf;
import vec::unsafe::from_buf;

struct image {
    let width: uint;
    let height: uint;
    let depth: uint;
    let data: ~[u8];

    new(width: uint, height: uint, depth: uint, -data: ~[u8]) {
        self.width = width;
        self.height = height;
        self.depth = depth;
        self.data = data;
    }
}

fn load(path: ~str) -> Option<image> unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let force_depth = 4 as c_int;
        let buffer = as_c_str(path, |bytes| {
            stbi_load(bytes, addr_of(width), addr_of(height), addr_of(depth), force_depth)
        });

        if is_null(buffer) {
            None
        } else {
            // FIXME: Shouldn't copy; instead we should use a sendable resource. They
            // aren't particularly safe yet though.
            let data = from_buf(buffer, (width * height * force_depth) as uint);
            libc::free(buffer as *c_void);
            Some(image(width as uint, height as uint, force_depth as uint, data))
        }
    }
}

fn load_from_memory(buffer: &[u8]) -> Option<image> unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let force_depth = 4 as c_int;
        let buffer = as_buf(buffer, |bytes, len| {
            stbi_load_from_memory(bytes, len as c_int, addr_of(width), addr_of(height), addr_of(depth), force_depth)
        });

        if is_null(buffer) {
            None
        } else {
            // FIXME: Shouldn't copy; instead we should use a sendable resource. They
            // aren't particularly safe yet though.
            let data = from_buf(buffer, (width * height * force_depth) as uint);
            libc::free(buffer as *c_void);
            Some(image(width as uint, height as uint, force_depth as uint, data))
        }
    }
}
<commit_msg>Fix build break<commit_after>import stb_image::*;
import stb_image::bindgen::*;
import libc::types::os::arch::c95::c_int;
import ptr::{addr_of, is_null};
import str::as_c_str;
import vec::as_buf;
import vec::unsafe::from_buf;

struct Image {
    width: uint,
    height: uint,
    depth: uint,
    data: ~[u8],
}

fn new_image(width: uint, height: uint, depth: uint, -data: ~[u8]) -> Image {
    Image {
        width : width,
        height : height,
        depth : depth,
        data : data,
    }
}

fn load(path: ~str) -> Option<Image> unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let force_depth = 4 as c_int;
        let buffer = as_c_str(path, |bytes| {
            stbi_load(bytes, addr_of(width), addr_of(height), addr_of(depth), force_depth)
        });

        if is_null(buffer) {
            None
        } else {
            // FIXME: Shouldn't copy; instead we should use a sendable resource. They
            // aren't particularly safe yet though.
            let data = from_buf(buffer, (width * height * force_depth) as uint);
            libc::free(buffer as *c_void);
            Some(new_image(width as uint, height as uint, force_depth as uint, data))
        }
    }
}

fn load_from_memory(buffer: &[u8]) -> Option<Image> unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let force_depth = 4 as c_int;
        let buffer = as_buf(buffer, |bytes, len| {
            stbi_load_from_memory(bytes, len as c_int, addr_of(width), addr_of(height), addr_of(depth), force_depth)
        });

        if is_null(buffer) {
            None
        } else {
            // FIXME: Shouldn't copy; instead we should use a sendable resource. They
            // aren't particularly safe yet though.
            let data = from_buf(buffer, (width * height * force_depth) as uint);
            libc::free(buffer as *c_void);
            Some(new_image(width as uint, height as uint, force_depth as uint, data))
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::BufRead;
use std::error::Error;

fn main() {
    let stdin = io::stdin();
    let mut ns: Vec<f64> = match read_floats(&mut stdin.lock()) {
        Ok(ns) => ns,
        Err(e) => panic!("failed to read numbers: {}", e),
    };

    ns.sort_by(|a, b| {
        match a.partial_cmp(b) {
            Some(o) => o,
            None => panic!("cannot compare {} and {}, thus cannort sort them", a, b),
        }
    });

    let count = ns.len();

    let sum = ns.iter().fold(0.0, |a, &b| a + b);

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum / count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999 / 1000]);
        println!("p99:   {}", ns[ns.len() * 99 / 100]);
        println!("p90:   {}", ns[ns.len() * 90 / 100]);
        println!("p50:   {}", ns[ns.len() * 50 / 100]);
        println!("min:   {}", ns[0]);
    }
}

fn read_floats(input: &mut io::BufRead) -> Result<Vec<f64>, Box<Error>> {
    let ns: Result<Vec<f64>, Box<Error>> = input
        .lines()
        .map(|line| -> Result<f64, Box<Error>> {
            Ok(line?.parse::<f64>()?)
        })
        .collect();

    ns
}
<commit_msg>rustfmt<commit_after>use std::io;
use std::io::BufRead;
use std::error::Error;

fn main() {
    let stdin = io::stdin();
    let mut ns: Vec<f64> = match read_floats(&mut stdin.lock()) {
        Ok(ns) => ns,
        Err(e) => panic!("failed to read numbers: {}", e),
    };

    ns.sort_by(|a, b| match a.partial_cmp(b) {
        Some(o) => o,
        None => panic!("cannot compare {} and {}, thus cannort sort them", a, b),
    });

    let count = ns.len();

    let sum = ns.iter().fold(0.0, |a, &b| a + b);

    println!("count: {}", count);
    println!("sum:   {}", sum);

    if ns.is_empty() {
        println!("(empty set of numbers, remaining stats not available)");
    } else {
        println!("avg:   {}", sum / count as f64);
        println!("max:   {}", ns[count - 1]);
        println!("p999:  {}", ns[ns.len() * 999 / 1000]);
        println!("p99:   {}", ns[ns.len() * 99 / 100]);
        println!("p90:   {}", ns[ns.len() * 90 / 100]);
        println!("p50:   {}", ns[ns.len() * 50 / 100]);
        println!("min:   {}", ns[0]);
    }
}

fn read_floats(input: &mut io::BufRead) -> Result<Vec<f64>, Box<Error>> {
    let ns: Result<Vec<f64>, Box<Error>> = input
        .lines()
        .map(|line| -> Result<f64, Box<Error>> {
            Ok(line?.parse::<f64>()?)
        })
        .collect();

    ns
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTPS CONNECT proxy!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
	let mut i = 0;
	let mut x = 0;
	let mut request = String::new();

	let srch = needle.as_bytes();

	if srch.len() == 0 {
		return request;
	}

	while buf[i] as char != '\0'  {
		if buf[i] as char == srch[0] as char {
			while x < srch.len() && buf[i] as char  == srch[x] as char {
				i = i + 1;
				x = x + 1;
			}
			break;
		} else {
			i = i + 1;
		}
	}

	if x == srch.len() {
		let mut end = i;
		while buf[end] as char != byte as char && buf[end] as char != '\n'
		{
			end = end + 1;

		}

		for y in i..end {
			request.push(buf[y] as char);
		}
	}

	return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn talk_to_me(mut instream: &TcpStream, mut outstream: &TcpStream, mut headers: &Header) -> usize
{

	let mut buf = [0u8; CHUNK];

	println!("top");

	let bytes = instream.read(&mut buf).unwrap();
	if bytes <= 0 {
		return 0;
	}

	let mut i = 0;

	println!("recv {}", bytes);

	for i in 0..bytes {
		print!("{}", buf[i] as char);
	}

	let mut chunk = 0;

	while chunk < bytes {
		let sent = outstream.write(&mut buf[0..bytes]).unwrap();
		if sent <= 0 {
			return 0;
		}
		println!("sent {}", sent);
		chunk = chunk + sent;
	}

	bytes
}

struct Header {
	pub hostname: String,
	pub connection: String,
	pub proxy: String,
	pub agent: String,
}

impl Header {

pub fn new() -> Header
{
	let hostname	 = String::new();
	let connection   = String::new();
	let proxy	 = String::new();
	let agent	 = String::new();

	let h = Header
	{
		hostname: hostname,
		connection: connection,
		proxy: proxy,
		agent: agent
	};

	return h;
}

}

fn http_connect_request(instream: TcpStream, headers: Header)
{
	let bogus_fix = &format!("{}", headers.hostname);

	let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();

	let mut tx = 1;

	let request = format!("HTTP/1.1 200 Connection established\r\nUser-Agent: {}\r\nProxy-Connection: {}\r\nConnection: {}\r\nHost: {}\r\n\r\n",
			headers.agent, headers.proxy, headers.connection, headers.hostname);

	let mut s = &instream;
	s.write(request.as_bytes()).unwrap(); // tell client the connection is made

	while tx != 0 {
		tx = talk_to_me(&instream, &outstream, &headers);
	}
	println!("tx is {}", tx);
}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{
	let mut i = 0;

	while buffer[i] != '\0' as u8
	{
		print!("{}", buffer[i] as char);
		i+=1;
	}
	print!("\n");

	if headers.hostname.is_empty()
	{
		headers.hostname = substr(buffer, "Host: ", '\r' as u8);
	}

	if headers.connection.is_empty()
	{
		headers.connection = substr(buffer, "Connection: ", '\r' as u8);
	}

	if headers.proxy.is_empty()
	{
		headers.proxy = substr(buffer, "Proxy-Connection: ", '\r' as u8);
	}

	if headers.agent.is_empty()
	{
		headers.agent = substr(buffer, "User-Agent: ", '\r' as u8);
	}

	if ! headers.hostname.is_empty() && ! headers.connection.is_empty()
		&& ! headers.proxy.is_empty() && ! headers.agent.is_empty()
	{

		return true;
	}

	return false;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
	 loop
	{
		let mut buffer = [0u8; REQUEST_LEN];
		let mut byte = [0u8; 1];
		let mut len = 0;

		while byte[0] as char != '\n'
		{
			let bytes = instream.read(&mut byte).unwrap();
			buffer[len] = byte[0];
			len += bytes;
		}

		buffer[len] = '\0' as u8;

		if check_headers(buffer, headers) && len == 2
		{
			let mut i = 0;

			while i < REQUEST_LEN
			{
				buffer[i] = 0;
				i += 1;
			}
			return;
		}
	}

}

fn request_method(mut instream: &TcpStream) -> String
{
	let mut byte = [0u8;1];

	let mut method: String = String::new();

	// bit better for now it'll do!
	while byte[0] as char != ' '
	{
		instream.read(&mut byte).unwrap();
		if byte[0] as char != ' '
		{
			method.push(byte[0] as char);
		}
	}

	match method.as_ref()
	{
		"CONNECT" =>
		{
			return method;
		}

		"GET" | "POST" | "OPTIONS" | "HEAD" =>
		{
			return "".to_string();
			// all good do not return!!!
		}

		_ =>
		{
			return "".to_string();
		}
	}
}

fn proxy(stream: TcpStream) {
	let method = request_method(&stream);

	match method.as_ref()
	{
		"CONNECT" =>
		{
			let mut headers = Header::new();
			request_headers(&stream, &mut headers);

			http_connect_request(stream, headers);
		}

		_ =>
		{
			println!("REQUEST UNKNOWN");
		}
	}
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
	let ip = Ipv4Addr::new(127, 0, 0, 1);
	let host = SocketAddrV4::new(ip, port);
	let listener = TcpListener::bind(host).unwrap();

	let pool = ThreadPool::new(threads);

	for mut stream in listener.incoming()
	{
		match stream
		{
			Ok(stream) =>
			{
				pool.execute(move || { proxy(stream); });
			}

			Err(_) =>
			{
				println!("NET error");
				1 << 7;
			}
		}
	}

	drop (listener);
}

fn main () {
	let threads = 128;
	let port: u16 = 9998;

	proxy_time(port, threads);
	println!("Blocking all badness");
}

<commit_msg>blah blah<commit_after>/*
  Copyright (c) 2015, Al Poole <netstar@gmail.com>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
*/

//   This is a HTTPS CONNECT proxy!

use std::string::{String};
use std::net::{SocketAddrV4,Ipv4Addr,TcpListener,TcpStream};
use std::io::{Write, Read};

const REQUEST_LEN: usize = 65535;

fn substr(buf: [u8;REQUEST_LEN], needle: &str, byte: u8) -> String
{
	let mut i = 0;
	let mut x = 0;
	let mut request = String::new();

	let srch = needle.as_bytes();

	if srch.len() == 0 {
		return request;
	}

	while buf[i] as char != '\0'  {
		if buf[i] as char == srch[0] as char {
			while x < srch.len() && buf[i] as char  == srch[x] as char {
				i = i + 1;
				x = x + 1;
			}
			break;
		} else {
			i = i + 1;
		}
	}

	if x == srch.len() {
		let mut end = i;
		while buf[end] as char != byte as char && buf[end] as char != '\n'
		{
			end = end + 1;

		}

		for y in i..end {
			request.push(buf[y] as char);
		}
	}

	return request;
}

const CHUNK: usize = 4096; // PAGESIZEish

fn talk_to_me(mut instream: &TcpStream, mut outstream: &TcpStream, mut headers: &Header) -> bool
{

	let mut buf = [0u8; CHUNK];

	println!("top");
	let bytes = instream.read(&mut buf).unwrap();
	if bytes <= 0 {
		return false;
	}

	println!("recv {}", bytes);

	for i in 0..bytes {
		print!("{}", buf[i] as char);
	}

	let mut chunk = 0;

	while chunk < bytes {
		let sent = outstream.write(&mut buf[0..bytes]).unwrap();
		if sent <= 0 {
			return false;
		}
		println!("sent {}", sent);
		chunk = chunk + sent;
	}
	true
}

struct Header {
	pub hostname: String,
	pub connection: String,
	pub proxy: String,
	pub agent: String,
}

impl Header {

pub fn new() -> Header
{
	let hostname	 = String::new();
	let connection   = String::new();
	let proxy	 = String::new();
	let agent	 = String::new();

	let h = Header
	{
		hostname: hostname,
		connection: connection,
		proxy: proxy,
		agent: agent
	};

	return h;
}

}

fn http_connect_request(instream: TcpStream, headers: Header)
{
	let bogus_fix = &format!("{}", headers.hostname);

	let outstream = TcpStream::connect::<(&str)>(bogus_fix).unwrap();
	let mut disconnected = false;

	let request = format!("HTTP/1.1 200 Connection established\r\nUser-Agent: {}\r\nProxy-Connection: {}\r\nConnection: {}\r\nHost: {}\r\n\r\n",
			headers.agent, headers.proxy, headers.connection, headers.hostname);

	let mut s = &instream;
	s.write(request.as_bytes()).unwrap(); // tell client the connection is made

	while ! disconnected {
		disconnected = talk_to_me(&instream, &outstream, &headers);
	}
}

fn check_headers(buffer: [u8;REQUEST_LEN], headers: &mut Header) -> bool
{
	let mut i = 0;

	while buffer[i] != '\0' as u8
	{
		print!("{}", buffer[i] as char);
		i+=1;
	}
	print!("\n");

	if headers.hostname.is_empty()
	{
		headers.hostname = substr(buffer, "Host: ", '\r' as u8);
	}

	if headers.connection.is_empty()
	{
		headers.connection = substr(buffer, "Connection: ", '\r' as u8);
	}

	if headers.proxy.is_empty()
	{
		headers.proxy = substr(buffer, "Proxy-Connection: ", '\r' as u8);
	}

	if headers.agent.is_empty()
	{
		headers.agent = substr(buffer, "User-Agent: ", '\r' as u8);
	}

	if ! headers.hostname.is_empty() && ! headers.connection.is_empty()
		&& ! headers.proxy.is_empty() && ! headers.agent.is_empty()
	{

		return true;
	}

	return false;
}

fn request_headers(mut instream: &TcpStream, headers: &mut Header)
{
	 loop
	{
		let mut buffer = [0u8; REQUEST_LEN];
		let mut byte = [0u8; 1];
		let mut len = 0;

		while byte[0] as char != '\n'
		{
			let bytes = instream.read(&mut byte).unwrap();
			buffer[len] = byte[0];
			len += bytes;
		}

		buffer[len] = '\0' as u8;

		if check_headers(buffer, headers) && len == 2
		{
			let mut i = 0;

			while i < REQUEST_LEN
			{
				buffer[i] = 0;
				i += 1;
			}
			return;
		}
	}

}

fn request_method(mut instream: &TcpStream) -> String
{
	let mut byte = [0u8;1];

	let mut method: String = String::new();

	// bit better for now it'll do!
	while byte[0] as char != ' '
	{
		instream.read(&mut byte).unwrap();
		if byte[0] as char != ' '
		{
			method.push(byte[0] as char);
		}
	}

	match method.as_ref()
	{
		"CONNECT" =>
		{
			return method;
		}

		"GET" | "POST" | "OPTIONS" | "HEAD" =>
		{
			return "".to_string();
			// all good do not return!!!
		}

		_ =>
		{
			return "".to_string();
		}
	}
}

fn proxy(stream: TcpStream) {
	let method = request_method(&stream);

	match method.as_ref()
	{
		"CONNECT" =>
		{
			let mut headers = Header::new();
			request_headers(&stream, &mut headers);

			http_connect_request(stream, headers);
		}

		_ =>
		{
			println!("REQUEST UNKNOWN");
		}
	}
}

extern crate threadpool;
use threadpool::ThreadPool;

fn proxy_time(port: u16, threads: usize) {
	let ip = Ipv4Addr::new(127, 0, 0, 1);
	let host = SocketAddrV4::new(ip, port);
	let listener = TcpListener::bind(host).unwrap();

	let pool = ThreadPool::new(threads);

	for stream in listener.incoming()
	{
		match stream
		{
			Ok(stream) =>
			{
				pool.execute(move || { proxy(stream); });
			}

			Err(_) =>
			{
				println!("NET error");
				1 << 7;
			}
		}
	}

	drop (listener);
}

fn main () {
	let threads = 128;
	let port: u16 = 9998;

	proxy_time(port, threads);
	println!("Blocking all badness");
}

<|endoftext|>


<commit_before>extern crate decimal;

use decimal::*;
use std::fs::File;
use std::path::Path;
use std::io::BufRead;
use std::io::BufReader;

fn find_end_quote(s: &str, quote: char) -> Option<usize> {
    match s.find(quote) {
        None => None,
        Some(i) => {
            match s[i+1..].chars().next() {
                None => Some(i),
                Some(c) if c == quote => find_end_quote(&s[i+2..], quote).and_then(|j| { Some(i + 2 + j) }),
                Some(_) => Some(i),
            }
        }
    }
}

fn split_token<'a>(line: &'a str) -> (&'a str, &'a str) {
    let line = line.trim_left();
    if line.starts_with("--") {
        ("", "")
    } else if line.starts_with("\"") {
        let end = find_end_quote(&line[1..], '"').expect("Unmatched double quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else if line.starts_with("'") {
        let end = find_end_quote(&line[1..], '\'').expect("Unmatched single quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else {
        match line.find(char::is_whitespace) {
            None => (line, ""),
            Some(end) => (&line[0..end], &line[end + 1..]),
        }
    }
}

#[derive(Debug)]
struct Scanner<'a> {
    current: &'a str,
    remaining: &'a str,
}

impl<'a> Scanner<'a> {
    pub fn new(line: &'a str) -> Scanner<'a> {
        Scanner {
            current: "",
            remaining: line,
        }
    }

    pub fn current(&self) -> &'a str {
        self.current
    }

    pub fn remaining(&self) -> &'a str {
        self.remaining
    }

    pub fn next(&mut self) -> &'a str {
        let (current, remaining) = split_token(self.remaining);
        self.current = current;
        self.remaining = remaining;
        self.current
    }
}

#[derive(Debug)]
enum Directive<'a> {
    Precision(isize),
    Rounding(Rounding),
    MaxExponent(isize),
    MinExponent(isize),
    Version(&'a str),
    Extended(bool),
    Clamp(bool),
    Test(&'a str),
}

#[derive(Debug)]
enum Op<'a> {
    Abs(&'a str),
    Add(&'a str, &'a str),
    And(&'a str, &'a str),
    Apply(&'a str),
    Canonical(&'a str),
    Class(&'a str),
    Compare(&'a str, &'a str),
    CompareSig(&'a str, &'a str),
    CompareTotal(&'a str, &'a str),
    CompareTotalMag(&'a str, &'a str),
    Copy(&'a str),
    CopyAbs(&'a str),
    CopyNegate(&'a str),
    CopySign(&'a str, &'a str),
    Divide(&'a str, &'a str),
    DivideInt(&'a str, &'a str),
    Exp(&'a str),
    Fma(&'a str, &'a str, &'a str),
    Invert(&'a str),
    Ln(&'a str),
    Log10(&'a str),
    LogB(&'a str),
    Max(&'a str, &'a str),
    MaxMag(&'a str, &'a str),
    Min(&'a str, &'a str),
    MinMag(&'a str, &'a str),
    Minus(&'a str),
    Multiply(&'a str, &'a str),
    NextMinus(&'a str),
    NextPlus(&'a str),
    NextToward(&'a str, &'a str),
    Or(&'a str, &'a str),
    Plus(&'a str),
    Power(&'a str, &'a str),
    Quantize(&'a str, &'a str),
    Reduce(&'a str),
    Remainder(&'a str, &'a str),
    RemainderNear(&'a str, &'a str),
    Rescale(&'a str, &'a str),
    Rotate(&'a str, &'a str),
    SameQuantum(&'a str, &'a str),
    ScaleB(&'a str, &'a str),
    Shift(&'a str, &'a str),
    SquareRoot(&'a str),
    Subtract(&'a str, &'a str),
    ToEng(&'a str),
    ToIntegral(&'a str),
    ToIntegralExact(&'a str),
    ToSci(&'a str),
    Trim(&'a str),
    Xor(&'a str, &'a str),
}

#[derive(Debug)]
struct Test<'a> {
    id: &'a str,
    op: Op<'a>,
    result: &'a str,
    conditions: Status,
}

#[derive(Debug)]
enum Instr<'a> {
    Directive(Directive<'a>),
    Test(Test<'a>),
}

fn parse_directive<'a>(s: &mut Scanner<'a>) -> Directive<'a> {
    let keyword = s.current().trim_right_matches(':').to_lowercase();
    match keyword.as_ref() {
        "precision" => {
            let val = s.next().parse::<isize>().expect("No value for precision");
            Directive::Precision(val)
        }
        "rounding" => {
            Directive::Rounding(match s.next() {
                "ceiling" => Rounding::Ceiling,
                "down" => Rounding::Down,
                "floor" => Rounding::Floor,
                "half_down" => Rounding::HalfDown,
                "half_even" => Rounding::HalfEven,
                "half_up" => Rounding::HalfUp,
                "up" => Rounding::Up,
                "05up" => Rounding::ZeroOrFiveUp,
                err => panic!("Unknown rounding mode {}", err),
            })
        }
        "maxexponent" => {
            let val = s.next()
                       .trim_left_matches('+')
                       .parse::<isize>()
                       .expect("No value for maxexponent");
            Directive::MaxExponent(val)
        }
        "minexponent" => {
            let val = s.next().parse::<isize>().expect("No value for minexponent");
            Directive::MinExponent(val)
        }
        "version" => {
            Directive::Version(s.next())
        }
        "extended" => {
            let val = s.next().parse::<isize>().expect("No value for extended");
            Directive::Extended(val != 0)
        }
        "clamp" => {
            let val = s.next().parse::<isize>().expect("No value for clamp");
            Directive::Clamp(val != 0)
        }
        "dectest" => {
            Directive::Test(s.next())
        }
        _ => panic!("Cannot parse directive {} {}", s.current(), s.remaining()),
    }
}

fn parse_test<'a>(s: &mut Scanner<'a>) -> Test<'a> {
    let id = s.current();
    let op = match s.next().to_lowercase().as_ref() {
        "abs" => Op::Abs(s.next()),
        "add" => Op::Add(s.next(), s.next()),
        "and" => Op::And(s.next(), s.next()),
        "apply" => Op::Apply(s.next()),
        "canonical" => Op::Canonical(s.next()),
        "class" => Op::Class(s.next()),
        "compare" => Op::Compare(s.next(), s.next()),
        "comparesig" => Op::CompareSig(s.next(), s.next()),
        "comparetotal" => Op::CompareTotal(s.next(), s.next()),
        "comparetotmag" => Op::CompareTotalMag(s.next(), s.next()),
        "copy" => Op::Copy(s.next()),
        "copyabs" => Op::CopyAbs(s.next()),
        "copynegate" => Op::CopyNegate(s.next()),
        "copysign" => Op::CopySign(s.next(), s.next()),
        "divide" => Op::Divide(s.next(), s.next()),
        "divideint" => Op::DivideInt(s.next(), s.next()),
        "exp" => Op::Exp(s.next()),
        "fma" => Op::Fma(s.next(), s.next(), s.next()),
        "invert" => Op::Invert(s.next()),
        "ln" => Op::Ln(s.next()),
        "log10" => Op::Log10(s.next()),
        "logb" => Op::LogB(s.next()),
        "max" => Op::Max(s.next(), s.next()),
        "maxmag" => Op::MaxMag(s.next(), s.next()),
        "min" => Op::Min(s.next(), s.next()),
        "minmag" => Op::MinMag(s.next(), s.next()),
        "minus" => Op::Minus(s.next()),
        "multiply" => Op::Multiply(s.next(), s.next()),
        "nextminus" => Op::NextMinus(s.next()),
        "nextplus" => Op::NextPlus(s.next()),
        "nexttoward" => Op::NextToward(s.next(), s.next()),
        "or" => Op::Or(s.next(), s.next()),
        "plus" => Op::Plus(s.next()),
        "power" => Op::Power(s.next(), s.next()),
        "quantize" => Op::Quantize(s.next(), s.next()),
        "reduce" => Op::Reduce(s.next()),
        "remainder" => Op::Remainder(s.next(), s.next()),
        "remaindernear" => Op::RemainderNear(s.next(), s.next()),
        "rescale" => Op::Rescale(s.next(), s.next()),
        "rotate" => Op::Rotate(s.next(), s.next()),
        "samequantum" => Op::SameQuantum(s.next(), s.next()),
        "scaleb" => Op::ScaleB(s.next(), s.next()),
        "shift" => Op::Shift(s.next(), s.next()),
        "squareroot" => Op::SquareRoot(s.next()),
        "subtract" => Op::Subtract(s.next(), s.next()),
        "toeng" => Op::ToEng(s.next()),
        "tointegral" => Op::ToIntegral(s.next()),
        "tointegralx" => Op::ToIntegralExact(s.next()),
        "tosci" => Op::ToSci(s.next()),
        "trim" => Op::Trim(s.next()),
        "xor" => Op::Xor(s.next(), s.next()),
        err => panic!("Unknown op {}", err),
    };
    if s.next() != "->" {
        panic!("Missing -> [{} {}]", s.current(), s.remaining());
    }
    let result = s.next();
    let mut status = Status::empty();
    loop {
        let cond = s.next().to_lowercase();
        if cond.is_empty() {
            break;
        }
        status = status |
                 match cond.as_ref() {
            "conversion_syntax" => CONVERSION_SYNTAX,
            "division_by_zero" => DIVISION_BY_ZERO,
            "division_impossible" => DIVISION_IMPOSSIBLE,
            "division_undefined" => DIVISION_UNDEFINED,
            "insufficient_storage" => INSUFFICIENT_STORAGE,
            "inexact" => INEXACT,
            "invalid_context" => INVALID_CONTEXT,
            "invalid_operation" => INVALID_OPERATION,
            "lost_digits" => LOST_DIGITS,
            "overflow" => OVERFLOW,
            "clamped" => CLAMPED,
            "rounded" => ROUNDED,
            "subnormal" => SUBNORMAL,
            "underflow" => UNDERFLOW,
            _ => panic!("Cannot parse condition {}", s.current()),
        }
    }
    Test {
        id: id,
        op: op,
        result: result,
        conditions: status,
    }
}

fn parse_line<'a>(line: &'a str) -> Option<Instr<'a>> {
    let mut scanner = Scanner::new(line);
    match scanner.next() {
        "" => None,
        token if token.starts_with("--") => None,
        token if token.ends_with(":") => Some(Instr::Directive(parse_directive(&mut scanner))),
        _ => Some(Instr::Test(parse_test(&mut scanner))),
    }
}

fn run_test(path: &Path) {
    let file = File::open(path);
    println!("{:?}", file);
    for line in BufReader::new(File::open(path).unwrap()).lines() {
        let line = line.unwrap();
        println!("{}", line);
        println!("\t{:?}", parse_line(&line));
    }
}

fn main() {
    let filepath = std::env::args().nth(1).expect("Filename to test");
    let path = Path::new(&filepath);
    run_test(path);
}
<commit_msg>Rename function to read_test.<commit_after>extern crate decimal;

use decimal::*;
use std::fs::File;
use std::path::Path;
use std::io::BufRead;
use std::io::BufReader;

fn find_end_quote(s: &str, quote: char) -> Option<usize> {
    match s.find(quote) {
        None => None,
        Some(i) => {
            match s[i+1..].chars().next() {
                None => Some(i),
                Some(c) if c == quote => find_end_quote(&s[i+2..], quote).and_then(|j| { Some(i + 2 + j) }),
                Some(_) => Some(i),
            }
        }
    }
}

fn split_token<'a>(line: &'a str) -> (&'a str, &'a str) {
    let line = line.trim_left();
    if line.starts_with("--") {
        ("", "")
    } else if line.starts_with("\"") {
        let end = find_end_quote(&line[1..], '"').expect("Unmatched double quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else if line.starts_with("'") {
        let end = find_end_quote(&line[1..], '\'').expect("Unmatched single quote") + 1;
        (&line[1..end], &line[end + 1..])
    } else {
        match line.find(char::is_whitespace) {
            None => (line, ""),
            Some(end) => (&line[0..end], &line[end + 1..]),
        }
    }
}

#[derive(Debug)]
struct Scanner<'a> {
    current: &'a str,
    remaining: &'a str,
}

impl<'a> Scanner<'a> {
    pub fn new(line: &'a str) -> Scanner<'a> {
        Scanner {
            current: "",
            remaining: line,
        }
    }

    pub fn current(&self) -> &'a str {
        self.current
    }

    pub fn remaining(&self) -> &'a str {
        self.remaining
    }

    pub fn next(&mut self) -> &'a str {
        let (current, remaining) = split_token(self.remaining);
        self.current = current;
        self.remaining = remaining;
        self.current
    }
}

#[derive(Debug)]
enum Directive<'a> {
    Precision(isize),
    Rounding(Rounding),
    MaxExponent(isize),
    MinExponent(isize),
    Version(&'a str),
    Extended(bool),
    Clamp(bool),
    Test(&'a str),
}

#[derive(Debug)]
enum Op<'a> {
    Abs(&'a str),
    Add(&'a str, &'a str),
    And(&'a str, &'a str),
    Apply(&'a str),
    Canonical(&'a str),
    Class(&'a str),
    Compare(&'a str, &'a str),
    CompareSig(&'a str, &'a str),
    CompareTotal(&'a str, &'a str),
    CompareTotalMag(&'a str, &'a str),
    Copy(&'a str),
    CopyAbs(&'a str),
    CopyNegate(&'a str),
    CopySign(&'a str, &'a str),
    Divide(&'a str, &'a str),
    DivideInt(&'a str, &'a str),
    Exp(&'a str),
    Fma(&'a str, &'a str, &'a str),
    Invert(&'a str),
    Ln(&'a str),
    Log10(&'a str),
    LogB(&'a str),
    Max(&'a str, &'a str),
    MaxMag(&'a str, &'a str),
    Min(&'a str, &'a str),
    MinMag(&'a str, &'a str),
    Minus(&'a str),
    Multiply(&'a str, &'a str),
    NextMinus(&'a str),
    NextPlus(&'a str),
    NextToward(&'a str, &'a str),
    Or(&'a str, &'a str),
    Plus(&'a str),
    Power(&'a str, &'a str),
    Quantize(&'a str, &'a str),
    Reduce(&'a str),
    Remainder(&'a str, &'a str),
    RemainderNear(&'a str, &'a str),
    Rescale(&'a str, &'a str),
    Rotate(&'a str, &'a str),
    SameQuantum(&'a str, &'a str),
    ScaleB(&'a str, &'a str),
    Shift(&'a str, &'a str),
    SquareRoot(&'a str),
    Subtract(&'a str, &'a str),
    ToEng(&'a str),
    ToIntegral(&'a str),
    ToIntegralExact(&'a str),
    ToSci(&'a str),
    Trim(&'a str),
    Xor(&'a str, &'a str),
}

#[derive(Debug)]
struct Test<'a> {
    id: &'a str,
    op: Op<'a>,
    result: &'a str,
    conditions: Status,
}

#[derive(Debug)]
enum Instr<'a> {
    Directive(Directive<'a>),
    Test(Test<'a>),
}

fn parse_directive<'a>(s: &mut Scanner<'a>) -> Directive<'a> {
    let keyword = s.current().trim_right_matches(':').to_lowercase();
    match keyword.as_ref() {
        "precision" => {
            let val = s.next().parse::<isize>().expect("No value for precision");
            Directive::Precision(val)
        }
        "rounding" => {
            Directive::Rounding(match s.next() {
                "ceiling" => Rounding::Ceiling,
                "down" => Rounding::Down,
                "floor" => Rounding::Floor,
                "half_down" => Rounding::HalfDown,
                "half_even" => Rounding::HalfEven,
                "half_up" => Rounding::HalfUp,
                "up" => Rounding::Up,
                "05up" => Rounding::ZeroOrFiveUp,
                err => panic!("Unknown rounding mode {}", err),
            })
        }
        "maxexponent" => {
            let val = s.next()
                       .trim_left_matches('+')
                       .parse::<isize>()
                       .expect("No value for maxexponent");
            Directive::MaxExponent(val)
        }
        "minexponent" => {
            let val = s.next().parse::<isize>().expect("No value for minexponent");
            Directive::MinExponent(val)
        }
        "version" => {
            Directive::Version(s.next())
        }
        "extended" => {
            let val = s.next().parse::<isize>().expect("No value for extended");
            Directive::Extended(val != 0)
        }
        "clamp" => {
            let val = s.next().parse::<isize>().expect("No value for clamp");
            Directive::Clamp(val != 0)
        }
        "dectest" => {
            Directive::Test(s.next())
        }
        _ => panic!("Cannot parse directive {} {}", s.current(), s.remaining()),
    }
}

fn parse_test<'a>(s: &mut Scanner<'a>) -> Test<'a> {
    let id = s.current();
    let op = match s.next().to_lowercase().as_ref() {
        "abs" => Op::Abs(s.next()),
        "add" => Op::Add(s.next(), s.next()),
        "and" => Op::And(s.next(), s.next()),
        "apply" => Op::Apply(s.next()),
        "canonical" => Op::Canonical(s.next()),
        "class" => Op::Class(s.next()),
        "compare" => Op::Compare(s.next(), s.next()),
        "comparesig" => Op::CompareSig(s.next(), s.next()),
        "comparetotal" => Op::CompareTotal(s.next(), s.next()),
        "comparetotmag" => Op::CompareTotalMag(s.next(), s.next()),
        "copy" => Op::Copy(s.next()),
        "copyabs" => Op::CopyAbs(s.next()),
        "copynegate" => Op::CopyNegate(s.next()),
        "copysign" => Op::CopySign(s.next(), s.next()),
        "divide" => Op::Divide(s.next(), s.next()),
        "divideint" => Op::DivideInt(s.next(), s.next()),
        "exp" => Op::Exp(s.next()),
        "fma" => Op::Fma(s.next(), s.next(), s.next()),
        "invert" => Op::Invert(s.next()),
        "ln" => Op::Ln(s.next()),
        "log10" => Op::Log10(s.next()),
        "logb" => Op::LogB(s.next()),
        "max" => Op::Max(s.next(), s.next()),
        "maxmag" => Op::MaxMag(s.next(), s.next()),
        "min" => Op::Min(s.next(), s.next()),
        "minmag" => Op::MinMag(s.next(), s.next()),
        "minus" => Op::Minus(s.next()),
        "multiply" => Op::Multiply(s.next(), s.next()),
        "nextminus" => Op::NextMinus(s.next()),
        "nextplus" => Op::NextPlus(s.next()),
        "nexttoward" => Op::NextToward(s.next(), s.next()),
        "or" => Op::Or(s.next(), s.next()),
        "plus" => Op::Plus(s.next()),
        "power" => Op::Power(s.next(), s.next()),
        "quantize" => Op::Quantize(s.next(), s.next()),
        "reduce" => Op::Reduce(s.next()),
        "remainder" => Op::Remainder(s.next(), s.next()),
        "remaindernear" => Op::RemainderNear(s.next(), s.next()),
        "rescale" => Op::Rescale(s.next(), s.next()),
        "rotate" => Op::Rotate(s.next(), s.next()),
        "samequantum" => Op::SameQuantum(s.next(), s.next()),
        "scaleb" => Op::ScaleB(s.next(), s.next()),
        "shift" => Op::Shift(s.next(), s.next()),
        "squareroot" => Op::SquareRoot(s.next()),
        "subtract" => Op::Subtract(s.next(), s.next()),
        "toeng" => Op::ToEng(s.next()),
        "tointegral" => Op::ToIntegral(s.next()),
        "tointegralx" => Op::ToIntegralExact(s.next()),
        "tosci" => Op::ToSci(s.next()),
        "trim" => Op::Trim(s.next()),
        "xor" => Op::Xor(s.next(), s.next()),
        err => panic!("Unknown op {}", err),
    };
    if s.next() != "->" {
        panic!("Missing -> [{} {}]", s.current(), s.remaining());
    }
    let result = s.next();
    let mut status = Status::empty();
    loop {
        let cond = s.next().to_lowercase();
        if cond.is_empty() {
            break;
        }
        status = status |
                 match cond.as_ref() {
            "conversion_syntax" => CONVERSION_SYNTAX,
            "division_by_zero" => DIVISION_BY_ZERO,
            "division_impossible" => DIVISION_IMPOSSIBLE,
            "division_undefined" => DIVISION_UNDEFINED,
            "insufficient_storage" => INSUFFICIENT_STORAGE,
            "inexact" => INEXACT,
            "invalid_context" => INVALID_CONTEXT,
            "invalid_operation" => INVALID_OPERATION,
            "lost_digits" => LOST_DIGITS,
            "overflow" => OVERFLOW,
            "clamped" => CLAMPED,
            "rounded" => ROUNDED,
            "subnormal" => SUBNORMAL,
            "underflow" => UNDERFLOW,
            _ => panic!("Cannot parse condition {}", s.current()),
        }
    }
    Test {
        id: id,
        op: op,
        result: result,
        conditions: status,
    }
}

fn parse_line<'a>(line: &'a str) -> Option<Instr<'a>> {
    let mut scanner = Scanner::new(line);
    match scanner.next() {
        "" => None,
        token if token.starts_with("--") => None,
        token if token.ends_with(":") => Some(Instr::Directive(parse_directive(&mut scanner))),
        _ => Some(Instr::Test(parse_test(&mut scanner))),
    }
}

fn read_test(path: &Path) {
    let file = File::open(path);
    println!("{:?}", file);
    for line in BufReader::new(File::open(path).unwrap()).lines() {
        let line = line.unwrap();
        println!("{}", line);
        println!("\t{:?}", parse_line(&line));
    }
}

fn main() {
    let filepath = std::env::args().nth(1).expect("Filename to test");
    let path = Path::new(&filepath);
    read_test(path);
}
<|endoftext|>