<commit_before>use regex::Regex;
use std::ascii::AsciiExt;
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Write, BufWriter};
use std::path::Path;

use snake_to_camel;

const PG_TYPE_H: &'static str = include_str!("pg_type.h");
const PG_RANGE_H: &'static str = include_str!("pg_range.h");

struct Type {
    name: &'static str,
    variant: String,
    kind: &'static str,
    element: u32,
    doc: String,
}

pub fn build() {
    let path = env::var_os("OUT_DIR").unwrap();
    let path: &Path = path.as_ref();
    let path = path.join("type.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    let ranges = parse_ranges();
    let types = parse_types(&ranges);

    make_enum(&mut file, &types);
    make_display_impl(&mut file);
    make_impl(&mut file, &types);
}

fn parse_ranges() -> BTreeMap<u32, u32> {
    let mut ranges = BTreeMap::new();

    for line in PG_RANGE_H.lines() {
        if !line.starts_with("DATA") {
            continue;
        }

        let split = line.split_whitespace().collect::<Vec<_>>();

        let oid = split[2].parse().unwrap();
        let element = split[3].parse().unwrap();

        ranges.insert(oid, element);
    }

    ranges
}

fn parse_types(ranges: &BTreeMap<u32, u32>) -> BTreeMap<u32, Type> {
    let doc_re = Regex::new(r#"DESCR\("([^"]+)"\)"#).unwrap();
    let range_vector_re = Regex::new("(range|vector)$").unwrap();
    let array_re = Regex::new("^_(.*)").unwrap();

    let mut types = BTreeMap::new();

    let mut lines = PG_TYPE_H.lines().peekable();
    while let Some(line) = lines.next() {
        if !line.starts_with("DATA") {
            continue;
        }

        let split = line.split_whitespace().collect::<Vec<_>>();

        let oid = split[3].parse().unwrap();

        let name = split[5];

        let variant = match name {
            "anyrange" => "Anyrange".to_owned(),
            name => {
                let variant = range_vector_re.replace(name, "_$1");
                let variant = array_re.replace(&variant, "$1_array");
                snake_to_camel(&variant)
            }
        };

        let kind = split[11];
        // we need to be able to pull composite fields and enum variants at runtime
        if kind == "C" || kind == "E" {
            continue;
        }

        let element = if let Some(&element) = ranges.get(&oid) {
            element
        } else {
            split[16].parse().unwrap()
        };

        let doc = array_re.replace(name, "$1[]");
        let mut doc = doc.to_ascii_uppercase();

        let descr = lines.peek()
                         .and_then(|line| doc_re.captures(line))
                         .and_then(|captures| captures.at(1));
        if let Some(descr) = descr {
            doc.push_str(" - ");
            doc.push_str(descr);
        }

        let type_ = Type {
            name: name,
            variant: variant,
            kind: kind,
            element: element,
            doc: doc,
        };

        types.insert(oid, type_);
    }

    types
}

fn make_enum(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
    write!(w,
r#"/// A Postgres type.
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {{
"#
           ).unwrap();

    for type_ in types.values() {
        write!(w,
r"    /// {}
    {},
"
               , type_.doc, type_.variant).unwrap();
    }

    write!(w,
r"    /// An unknown type.
    Other(Other),
}}

"         ).unwrap();
}

fn make_display_impl(w: &mut BufWriter<File>) {
    write!(w,
r#"impl fmt::Display for Type {{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {{
        match self.schema() {{
            "public" | "pg_catalog" => {{}}
            schema => try!(write!(fmt, "{{}}.", schema)),
        }}
        fmt.write_str(self.name())
    }}
}}

"#,
       ).unwrap();
}

fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
    write!(w,
"impl Type {{
    /// Returns the `Type` corresponding to the provided `Oid` if it
    /// corresponds to a built-in type.
    pub fn from_oid(oid: Oid) -> Option<Type> {{
        match oid {{
",
           ).unwrap();

    for (oid, type_) in types {
        write!(w,
"            {} => Some(Type::{}),
",
               oid, type_.variant).unwrap();
    }

    write!(w,
"            _ => None,
        }}
    }}

    /// Returns the OID of the `Type`.
    pub fn oid(&self) -> Oid {{
        match *self {{
",
           ).unwrap();

    for (oid, type_) in types {
        write!(w,
"            Type::{} => {},
",
               type_.variant, oid).unwrap();
    }

    write!(w,
"            Type::Other(ref u) => u.oid(),
        }}
    }}

    /// Returns the kind of this type.
    pub fn kind(&self) -> &Kind {{
        match *self {{
",
           ).unwrap();

    for type_ in types.values() {
        let kind = match type_.kind {
            "P" => "Pseudo".to_owned(),
            "A" => format!("Array(Type::{})", types[&type_.element].variant),
            "R" => format!("Range(Type::{})", types[&type_.element].variant),
            _ => "Simple".to_owned(),
        };

        write!(w,
"            Type::{} => {{
                const V: &'static Kind = &Kind::{};
                V
            }}
",
               type_.variant, kind).unwrap();
    }

    write!(w,
r#"            Type::Other(ref u) => u.kind(),
        }}
    }}

    /// Returns the schema of this type.
    pub fn schema(&self) -> &str {{
        match *self {{
            Type::Other(ref u) => u.schema(),
            _ => "pg_catalog",
        }}
    }}

    /// Returns the name of this type.
    pub fn name(&self) -> &str {{
        match *self {{
"#,
          ).unwrap();

    for type_ in types.values() {
        write!(w,
r#"            Type::{} => "{}",
"#,
               type_.variant, type_.name).unwrap();
    }

    write!(w,
"            Type::Other(ref u) => u.name(),
        }}
    }}
}}
"
           ).unwrap();
}
<commit_msg>Cleanup<commit_after>use regex::Regex;
use std::ascii::AsciiExt;
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Write, BufWriter};
use std::path::Path;

use snake_to_camel;

const PG_TYPE_H: &'static str = include_str!("pg_type.h");
const PG_RANGE_H: &'static str = include_str!("pg_range.h");

struct Type {
    name: &'static str,
    variant: String,
    kind: &'static str,
    element: u32,
    doc: String,
}

pub fn build() {
    let path = env::var_os("OUT_DIR").unwrap();
    let path: &Path = path.as_ref();
    let path = path.join("type.rs");
    let mut file = BufWriter::new(File::create(&path).unwrap());

    let ranges = parse_ranges();
    let types = parse_types(&ranges);

    make_enum(&mut file, &types);
    make_display_impl(&mut file);
    make_impl(&mut file, &types);
}

fn parse_ranges() -> BTreeMap<u32, u32> {
    let mut ranges = BTreeMap::new();

    for line in PG_RANGE_H.lines() {
        if !line.starts_with("DATA") {
            continue;
        }

        let split = line.split_whitespace().collect::<Vec<_>>();

        let oid = split[2].parse().unwrap();
        let element = split[3].parse().unwrap();

        ranges.insert(oid, element);
    }

    ranges
}

fn parse_types(ranges: &BTreeMap<u32, u32>) -> BTreeMap<u32, Type> {
    let doc_re = Regex::new(r#"DESCR\("([^"]+)"\)"#).unwrap();
    let range_vector_re = Regex::new("(range|vector)$").unwrap();
    let array_re = Regex::new("^_(.*)").unwrap();

    let mut types = BTreeMap::new();

    let mut lines = PG_TYPE_H.lines().peekable();
    while let Some(line) = lines.next() {
        if !line.starts_with("DATA") {
            continue;
        }

        let split = line.split_whitespace().collect::<Vec<_>>();

        let oid = split[3].parse().unwrap();

        let name = split[5];

        let variant = match name {
            "anyrange" => "Anyrange".to_owned(),
            name => {
                let variant = range_vector_re.replace(name, "_$1");
                let variant = array_re.replace(&variant, "$1_array");
                snake_to_camel(&variant)
            }
        };

        let kind = split[11];
        // we need to be able to pull composite fields and enum variants at runtime
        if kind == "C" || kind == "E" {
            continue;
        }

        let element = if let Some(&element) = ranges.get(&oid) {
            element
        } else {
            split[16].parse().unwrap()
        };

        let doc = array_re.replace(name, "$1[]");
        let mut doc = doc.to_ascii_uppercase();

        let descr = lines.peek()
                         .and_then(|line| doc_re.captures(line))
                         .and_then(|captures| captures.at(1));
        if let Some(descr) = descr {
            doc.push_str(" - ");
            doc.push_str(descr);
        }

        let type_ = Type {
            name: name,
            variant: variant,
            kind: kind,
            element: element,
            doc: doc,
        };

        types.insert(oid, type_);
    }

    types
}

fn make_enum(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
    write!(w,
"/// A Postgres type.
#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {{
"
           ).unwrap();

    for type_ in types.values() {
        write!(w,
"    /// {}
    {},
"
               , type_.doc, type_.variant).unwrap();
    }

    write!(w,
r"    /// An unknown type.
    Other(Other),
}}

"         ).unwrap();
}

fn make_display_impl(w: &mut BufWriter<File>) {
    write!(w,
r#"impl fmt::Display for Type {{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {{
        match self.schema() {{
            "public" | "pg_catalog" => {{}}
            schema => try!(write!(fmt, "{{}}.", schema)),
        }}
        fmt.write_str(self.name())
    }}
}}

"#,
       ).unwrap();
}

fn make_impl(w: &mut BufWriter<File>, types: &BTreeMap<u32, Type>) {
    write!(w,
"impl Type {{
    /// Returns the `Type` corresponding to the provided `Oid` if it
    /// corresponds to a built-in type.
    pub fn from_oid(oid: Oid) -> Option<Type> {{
        match oid {{
",
           ).unwrap();

    for (oid, type_) in types {
        write!(w,
"            {} => Some(Type::{}),
",
               oid, type_.variant).unwrap();
    }

    write!(w,
"            _ => None,
        }}
    }}

    /// Returns the OID of the `Type`.
    pub fn oid(&self) -> Oid {{
        match *self {{
",
           ).unwrap();

    for (oid, type_) in types {
        write!(w,
"            Type::{} => {},
",
               type_.variant, oid).unwrap();
    }

    write!(w,
"            Type::Other(ref u) => u.oid(),
        }}
    }}

    /// Returns the kind of this type.
    pub fn kind(&self) -> &Kind {{
        match *self {{
",
           ).unwrap();

    for type_ in types.values() {
        let kind = match type_.kind {
            "P" => "Pseudo".to_owned(),
            "A" => format!("Array(Type::{})", types[&type_.element].variant),
            "R" => format!("Range(Type::{})", types[&type_.element].variant),
            _ => "Simple".to_owned(),
        };

        write!(w,
"            Type::{} => {{
                const V: &'static Kind = &Kind::{};
                V
            }}
",
               type_.variant, kind).unwrap();
    }

    write!(w,
r#"            Type::Other(ref u) => u.kind(),
        }}
    }}

    /// Returns the schema of this type.
    pub fn schema(&self) -> &str {{
        match *self {{
            Type::Other(ref u) => u.schema(),
            _ => "pg_catalog",
        }}
    }}

    /// Returns the name of this type.
    pub fn name(&self) -> &str {{
        match *self {{
"#,
          ).unwrap();

    for type_ in types.values() {
        write!(w,
r#"            Type::{} => "{}",
"#,
               type_.variant, type_.name).unwrap();
    }

    write!(w,
"            Type::Other(ref u) => u.name(),
        }}
    }}
}}
"
           ).unwrap();
}
<|endoftext|>


<commit_before>use clap::App;
use std::default::Default;
use thud_game;
use thud_ui_common;
use thud_ui_console;

fn main() {
  let mut agents = thud_ui_common::agent_registry::AgentRegistry::new();
  agents
    .register(Box::new(
      thud_ui_common::agent_registry::StdinAgentBuilder::new(),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts1"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts2"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::FileAgentBuilder::new("file_agent"),
    ));

  // Set up arg handling.
  let matches = {
    let mut app = thud_ui_common::set_args(
      App::new("console_play")
        .version("0.1.0")
        .author("Stu Black <trurl@freeshell.org>")
        .about("Play Thud on the console"),
      &[
        thud_ui_common::FLAG_INITIAL_BOARD,
        thud_ui_common::FLAG_INITIAL_PLAYER,
        thud_ui_common::FLAG_LOG_LEVEL,
      ],
    );
    app = agents.register_args(app);
    app.get_matches()
  };
  let initial_cells = match matches
    .value_of(thud_ui_common::FLAG_INITIAL_BOARD)
    .map(|x| x.parse::<thud_ui_common::InitialBoard>())
  {
    None => thud_game::board::Cells::default(),
    Some(Ok(x)) => x.cells(),
    Some(Err(e)) => panic!("Bad initial board configuration: {}", e),
  };
  let logging_level = match matches
    .value_of(thud_ui_common::FLAG_LOG_LEVEL)
    .map(|x| x.parse::<log::LevelFilter>())
  {
    Some(Ok(x)) => x,
    Some(Err(_)) => panic!(
      "Bad logging level '{}'",
      matches.value_of(thud_ui_common::FLAG_LOG_LEVEL).unwrap()
    ),
    None => log::LevelFilter::Info,
  };

  // Set up logging.
  thud_ui_common::init::init_logger(logging_level);

  let mut agent1 = agents.get_player_1_from_arguments(&matches).unwrap();
  let mut agent2 = agents.get_player_2_from_arguments(&matches).unwrap();
  let mut state = thud_game::state::State::new(
    initial_cells,
    &thud_game::board::TRANSPOSITIONAL_EQUIVALENCE,
  );
  while !state.terminated() {
    println!("state: {:?}", state);
    let action = agent1.propose_action(&state).unwrap();
    println!("agent 1 proposes action: {:?}", action);
    state.do_action(&action);
    println!("state: {:?}", state);
    if state.terminated() {
      break;
    }
    let action = agent2.propose_action(&state).unwrap();
    println!("agent 2 proposes action: {:?}", action);
    state.do_action(&action);
  }
  println!("state has terminated: {:?}", state);

  // // Prompt for play.
  // loop {
  //   println!(
  //     "{:?} player's turn. Enter coordinate of piece to move.",
  //     human_role
  //   );
  //   let c = thud_ui_console::prompt_for_piece(state.cells(), human_role);
  //   let piece_actions: Vec<thud_game::Action> = state.position_actions(c).collect();
  //   if piece_actions.is_empty() {
  //     println!("Piece at {:?} has no actions.", c);
  //   } else {
  //     if let Some(action) = thud_ui_console::select_one(&piece_actions) {
  //       let mut moved_state = state.clone();
  //       moved_state.do_action(&action);
  //       println!(
  //         "After action, board: {}",
  //         thud_game::board::format_board(moved_state.cells())
  //       );
  //       println!("Is this okay?");
  //       match thud_ui_console::select_one(&["y", "n"]) {
  //         Some(&"y") => {
  //           state = moved_state;
  //           graph.retain_reachable_from(&[&state]);
  //           break;
  //         }
  //         _ => continue,
  //       }
  //     }
  //   }
  // }
}
<commit_msg>Print final game score along with game state in console_play.<commit_after>use clap::App;
use std::default::Default;
use thud_game;
use thud_ui_common;
use thud_ui_console;

fn main() {
  let mut agents = thud_ui_common::agent_registry::AgentRegistry::new();
  agents
    .register(Box::new(
      thud_ui_common::agent_registry::StdinAgentBuilder::new(),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts1"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::mcts::MctsAgentBuilder::new("mcts2"),
    ))
    .register(Box::new(
      thud_ui_common::agent_registry::FileAgentBuilder::new("file_agent"),
    ));

  // Set up arg handling.
  let matches = {
    let mut app = thud_ui_common::set_args(
      App::new("console_play")
        .version("0.1.0")
        .author("Stu Black <trurl@freeshell.org>")
        .about("Play Thud on the console"),
      &[
        thud_ui_common::FLAG_INITIAL_BOARD,
        thud_ui_common::FLAG_INITIAL_PLAYER,
        thud_ui_common::FLAG_LOG_LEVEL,
      ],
    );
    app = agents.register_args(app);
    app.get_matches()
  };
  let initial_cells = match matches
    .value_of(thud_ui_common::FLAG_INITIAL_BOARD)
    .map(|x| x.parse::<thud_ui_common::InitialBoard>())
  {
    None => thud_game::board::Cells::default(),
    Some(Ok(x)) => x.cells(),
    Some(Err(e)) => panic!("Bad initial board configuration: {}", e),
  };
  let logging_level = match matches
    .value_of(thud_ui_common::FLAG_LOG_LEVEL)
    .map(|x| x.parse::<log::LevelFilter>())
  {
    Some(Ok(x)) => x,
    Some(Err(_)) => panic!(
      "Bad logging level '{}'",
      matches.value_of(thud_ui_common::FLAG_LOG_LEVEL).unwrap()
    ),
    None => log::LevelFilter::Info,
  };

  // Set up logging.
  thud_ui_common::init::init_logger(logging_level);

  let mut agent1 = agents.get_player_1_from_arguments(&matches).unwrap();
  let mut agent2 = agents.get_player_2_from_arguments(&matches).unwrap();
  let mut state = thud_game::state::State::new(
    initial_cells,
    &thud_game::board::TRANSPOSITIONAL_EQUIVALENCE,
  );
  while !state.terminated() {
    println!("state: {:?}", state);
    let action = agent1.propose_action(&state).unwrap();
    println!("agent 1 proposes action: {:?}", action);
    state.do_action(&action);
    println!("state: {:?}", state);
    if state.terminated() {
      break;
    }
    let action = agent2.propose_action(&state).unwrap();
    println!("agent 2 proposes action: {:?}", action);
    state.do_action(&action);
  }
  println!("state has terminated: {:?}", state);
  println!(
    "final score: dwarfs {}, trolls {}",
    state.score(thud_game::Role::Dwarf),
    state.score(thud_game::Role::Troll)
  );

  // // Prompt for play.
  // loop {
  //   println!(
  //     "{:?} player's turn. Enter coordinate of piece to move.",
  //     human_role
  //   );
  //   let c = thud_ui_console::prompt_for_piece(state.cells(), human_role);
  //   let piece_actions: Vec<thud_game::Action> = state.position_actions(c).collect();
  //   if piece_actions.is_empty() {
  //     println!("Piece at {:?} has no actions.", c);
  //   } else {
  //     if let Some(action) = thud_ui_console::select_one(&piece_actions) {
  //       let mut moved_state = state.clone();
  //       moved_state.do_action(&action);
  //       println!(
  //         "After action, board: {}",
  //         thud_game::board::format_board(moved_state.cells())
  //       );
  //       println!("Is this okay?");
  //       match thud_ui_console::select_one(&["y", "n"]) {
  //         Some(&"y") => {
  //           state = moved_state;
  //           graph.retain_reachable_from(&[&state]);
  //           break;
  //         }
  //         _ => continue,
  //       }
  //     }
  //   }
  // }
}
<|endoftext|>


<commit_before>extern crate boxx;

#[cfg(test)]
mod tests {
  extern crate boxx;
  use boxx::expr::{Expr, boxx};
  extern crate env_logger;

  #[test]
  pub fn test_func() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(12), boxx("fn ttwo(a) { 2 * a }; ttwo(ttwo(3))"));

    assert_eq!(
      Expr::Int(41),
      boxx("
        fn foo(a) {
          a < 40 ? foo(a + 3) : a
        };

        foo(20)
      ")
    );

    assert_eq!(
      Expr::Int(21),
      boxx("
        fn fib(n) {
          n == 0 ? 0 : (n == 1 ? 1 : fib(n - 1) + fib(n - 2))
        };

        fib(8)
      ")
    );

    assert_eq!(
      Expr::Int(28),
      boxx("
        fn foo(a) {
          1 + a
        };

        fn bar(b) {
          5 * b
        };

        foo(bar(4)) + 7
      ")
    );

    assert_eq!(Expr::Int(12), boxx("fn foo(a) { 1 + a }; foo(4) + 7"));
    assert_eq!(Expr::Int(12), boxx("let foo = fn(a) { 1 + a }; foo(4) + 7"));

    assert_eq!(Expr::Int(2), boxx("fn foo() { 1 + 1 }; foo()"));
    assert_eq!(Expr::Int(7), boxx("fn foo() { 1 + 3 }; foo() + 3"));
    assert_eq!(Expr::Int(9), boxx("fn foo() { 1 + 3 }; fn bar() { foo() + 1}; 4 + bar()"));

    assert_eq!(Expr::Int(2), boxx("let foo = fn() { 1 + 1 }; foo()"));
    assert_eq!(Expr::Int(7), boxx("let foo = fn() { 1 + 3 }; foo() + 3"));
    assert_eq!(Expr::Int(9), boxx("let foo = fn() { 1 + 3 }; let bar = fn() { foo() + 1}; 4 + bar()"));
    // TODO: this should be parsed as a fn call assert_eq!(Expr::Int(4), boxx("fn() { 1 + 3 }()"));
    // TODO: have better failure message when ending a fn block with a semicolon
    // assert_eq!(Expr::Int(12), boxx("fn foo(a) { 1 + a; }; foo(4) + 7"));
    // TODO: recursion
  }

  #[test]
  pub fn test_const_decl() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(3), boxx("let x = 1 + 2; x"));
    assert_eq!(Expr::Int(1), boxx("let x = 1; x"));
    assert_eq!(Expr::Int(8), boxx("let x = 5; let y = 3; let z = x + y; z"));
  }

  #[test]
  pub fn test_ternary() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(1), boxx("true ? 1 : 0"));
    assert_eq!(Expr::Int(0), boxx("false ? 1 : 0"));
    assert_eq!(Expr::Int(3), boxx("(false ? 1 : 0); 1 + 2"));
    assert_eq!(Expr::Int(3), boxx("false ? 1 : 0; 1 + 2"));
    assert_eq!(Expr::Int(0), boxx("((1 + 1) > 3) ? 1 : 0"));
    assert_eq!(Expr::Int(14), boxx("((1 + 1) > 3) ? true && false : 12 + 2"));
    assert_eq!(Expr::Int(14), boxx("1 + 1 > 3 ? true && false : 12 + 2"));
    assert_eq!(
      Expr::Int(10),
      boxx(
          "(false || true) ? ((1 + 2 > 12) ? 9 : 10) : ((1 + 2 < 12) ? 6 : 7)"
       )
    );
    // same as above but without parens
    assert_eq!(
      Expr::Int(10),
      boxx(
          "false || true ? 1 + 2 > 12 ? 9 : 10 : 1 + 2 < 12 ? 6 : 7"
       )
    );

    assert_eq!(Expr::Bool(true), boxx("1 + 2 > (1 == 0 ? 5 : 1)"));

    assert_eq!(Expr::Int(-1), boxx("true;false ? 1;2 : 0;-1"));
  }

  #[test]
  pub fn test_seq() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(5), boxx("3;5"));
    //assert_eq!(Expr::Int(4), boxx("let x = 3;let y = 1;x + y"));
  }

  #[test]
  pub fn test_mod() {
    assert_eq!(Expr::Int(0), boxx("1 % 1"));
    assert_eq!(Expr::Int(2), boxx("7 % 5"));
    assert_eq!(Expr::Int(3), boxx("-7 % 5"));
    assert_eq!(Expr::Int(-2), boxx("-7 % -5"));
  }

  #[test]
  pub fn test_or_and_and() {
    assert_eq!(Expr::Bool(true), boxx("true && true"));
    assert_eq!(Expr::Bool(false), boxx("false && false"));
    assert_eq!(Expr::Bool(false), boxx("true && false"));
    assert_eq!(Expr::Bool(false), boxx("false && true"));

    assert_eq!(Expr::Bool(true), boxx("true || true"));
    assert_eq!(Expr::Bool(false), boxx("false || false"));
    assert_eq!(Expr::Bool(true), boxx("true || false"));
    assert_eq!(Expr::Bool(true), boxx("false || true"));
  }

  #[test]
  pub fn test_not_and_neg() {
    assert_eq!(Expr::Bool(true), boxx("!false"));

    assert_eq!(Expr::Bool(true), boxx("!(true == false)"));
    assert_eq!(Expr::Bool(true), boxx("!((1 == 1) == (3 <= 2))"));
    assert_eq!(Expr::Bool(false), boxx("!((1 == 1) == !(3 <= 2))"));
    assert_eq!(Expr::Bool(true), boxx("!!(!(!(true)))"));

    assert_eq!(Expr::Int(-1), boxx("-1"));
    assert_eq!(Expr::Int(-100), boxx("-(20 * 5)"));
    assert_eq!(Expr::Int(-100), boxx("-(-20 * -5)"));
    assert_eq!(Expr::Int(-100), boxx("(20 * -5)"));
    assert_eq!(Expr::Int(-100), boxx("(-20 * 5)"));
    assert_eq!(Expr::Int(100), boxx("(-20 * -5)"));
    assert_eq!(Expr::Int(100), boxx("-(20 * -5)"));
    assert_eq!(Expr::Int(100), boxx("-(-20 * 5)"));
    assert_eq!(Expr::Int(0), boxx("1 + -1"));
    assert_eq!(Expr::Int(2), boxx("1 - -1"));
    assert_eq!(Expr::Int(0), boxx("-1 - -1"));
    assert_eq!(Expr::Int(-2), boxx("-1 - 1"));
    assert_eq!(Expr::Int(-2), boxx("-1 * 2"));
    assert_eq!(Expr::Int(-2), boxx("2 * -1"));
    assert_eq!(Expr::Int(-2), boxx("-2 * 1"));
    assert_eq!(Expr::Int(-1), boxx("-(2 * 1) + 1"));
    assert_eq!(Expr::Int(1), boxx("(2 * 1) + -1"));
  }

  #[test]
  pub fn test_comparison_operators() {
    assert_eq!(Expr::Bool(true), boxx("1 == 1"));
    assert_eq!(Expr::Bool(false), boxx("1 == 2"));
    assert_eq!(Expr::Bool(false), boxx("(1 == 1) == (1 == 2)"));
    assert_eq!(Expr::Bool(true), boxx("(5 == 2) == (1 == 2)"));
    assert_eq!(Expr::Bool(true), boxx("(6 == 6) == true"));
    assert_eq!(Expr::Bool(false), boxx("1 == true"));
    assert_eq!(Expr::Bool(true), boxx("false == false"));

    assert_eq!(Expr::Bool(true), boxx("1 > 0"));
    assert_eq!(Expr::Bool(false), boxx("1 < 0"));

    assert_eq!(Expr::Bool(true), boxx("88 > 34"));
    assert_eq!(Expr::Bool(false), boxx("1 < 1"));
    assert_eq!(Expr::Bool(false), boxx("1 > 1"));

    assert_eq!(Expr::Bool(true), boxx("88 != 34"));
    assert_eq!(Expr::Bool(false), boxx("88 != 88"));
    assert_eq!(Expr::Bool(true), boxx("88 <= 88"));
    assert_eq!(Expr::Bool(true), boxx("88 >= 88"));
    assert_eq!(Expr::Bool(true), boxx("1 >= 0"));
    assert_eq!(Expr::Bool(false), boxx("1 >= 12"));

    assert_eq!(Expr::Bool(false), boxx("true != true"));
    assert_eq!(Expr::Bool(true), boxx("true != false"));
  }

  #[test]
  pub fn test_spaces() {
    assert_eq!(Expr::Int(2), boxx("1 + 1"));
    assert_eq!(Expr::Int(12), boxx(" (3+   3)* 2      "));
    assert_eq!(Expr::Int(7), boxx("1 + 3*(3 + (1 - 2))"));
  }

  #[test]
  pub fn test_eval_mult() {
    assert_eq!(Expr::Int(12), boxx("6*2"));
    assert_eq!(Expr::Int(12), boxx("(3+3)*2"));
    assert_eq!(Expr::Int(0), boxx("(3+3)*0"));
  }

  #[test]
  pub fn test_eval_div() {
    assert_eq!(Expr::Int(6), boxx("12/2"));
    //assert_eq!(Expr::Float(1.5), boxx("3/2"));
  }

  #[test]
  pub fn test_eval_addition() {
    assert_eq!(Expr::Int(3), boxx("1+2"));
    assert_eq!(Expr::Int(16), boxx("5+7+4"));
    assert_eq!(Expr::Int(-1), boxx("1-2"));
    assert_eq!(Expr::Int(-100), boxx("32-132"));
    assert_eq!(Expr::Int(-120), boxx("32-132-20"));

    assert_eq!(Expr::Int(-80), boxx("32-(132-20)"));

    assert_eq!(Expr::Int(-6), boxx("4-(7+3)"));
    assert_eq!(Expr::Int(0), boxx("4-(7-3)"));
    assert_eq!(Expr::Int(8), boxx("4+(7-3)"));
    assert_eq!(Expr::Int(8), boxx("(4+7)-3)"));
    assert_eq!(Expr::Int(0), boxx("(4-7)+3)"));
    assert_eq!(Expr::Int(14), boxx("(4+7)+3)"));

    assert_eq!(Expr::Int(2), boxx("(1-1)+(2-2)+(3-3)+((1+2)-((3-2)+1)+1)"));
    assert_eq!(Expr::Int(0), boxx("((((((((((1-1)))+1))))-1)))"));
  }
}
<commit_msg>test fn with two params<commit_after>extern crate boxx;

#[cfg(test)]
mod tests {
  extern crate boxx;
  use boxx::expr::{Expr, boxx};
  extern crate env_logger;

  #[test]
  pub fn test_func() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(12), boxx("fn sum(a, b) { a + b }; sum(sum(3, 4), 5)"));
    assert_eq!(Expr::Int(12), boxx("fn ttwo(a) { 2 * a }; ttwo(ttwo(3))"));

    assert_eq!(
      Expr::Int(41),
      boxx("
        fn foo(a) {
          a < 40 ? foo(a + 3) : a
        };

        foo(20)
      ")
    );

    assert_eq!(
      Expr::Int(21),
      boxx("
        fn fib(n) {
          n == 0 ? 0 : (n == 1 ? 1 : fib(n - 1) + fib(n - 2))
        };

        fib(8)
      ")
    );

    assert_eq!(
      Expr::Int(28),
      boxx("
        fn foo(a) {
          1 + a
        };

        fn bar(b) {
          5 * b
        };

        foo(bar(4)) + 7
      ")
    );

    assert_eq!(Expr::Int(12), boxx("fn foo(a) { 1 + a }; foo(4) + 7"));
    assert_eq!(Expr::Int(12), boxx("let foo = fn(a) { 1 + a }; foo(4) + 7"));

    assert_eq!(Expr::Int(2), boxx("fn foo() { 1 + 1 }; foo()"));
    assert_eq!(Expr::Int(7), boxx("fn foo() { 1 + 3 }; foo() + 3"));
    assert_eq!(Expr::Int(9), boxx("fn foo() { 1 + 3 }; fn bar() { foo() + 1}; 4 + bar()"));

    assert_eq!(Expr::Int(2), boxx("let foo = fn() { 1 + 1 }; foo()"));
    assert_eq!(Expr::Int(7), boxx("let foo = fn() { 1 + 3 }; foo() + 3"));
    assert_eq!(Expr::Int(9), boxx("let foo = fn() { 1 + 3 }; let bar = fn() { foo() + 1}; 4 + bar()"));
    // TODO: this should be parsed as a fn call assert_eq!(Expr::Int(4), boxx("fn() { 1 + 3 }()"));
    // TODO: have better failure message when ending a fn block with a semicolon
    // assert_eq!(Expr::Int(12), boxx("fn foo(a) { 1 + a; }; foo(4) + 7"));
    // TODO: recursion
  }

  #[test]
  pub fn test_const_decl() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(3), boxx("let x = 1 + 2; x"));
    assert_eq!(Expr::Int(1), boxx("let x = 1; x"));
    assert_eq!(Expr::Int(8), boxx("let x = 5; let y = 3; let z = x + y; z"));
  }

  #[test]
  pub fn test_ternary() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(1), boxx("true ? 1 : 0"));
    assert_eq!(Expr::Int(0), boxx("false ? 1 : 0"));
    assert_eq!(Expr::Int(3), boxx("(false ? 1 : 0); 1 + 2"));
    assert_eq!(Expr::Int(3), boxx("false ? 1 : 0; 1 + 2"));
    assert_eq!(Expr::Int(0), boxx("((1 + 1) > 3) ? 1 : 0"));
    assert_eq!(Expr::Int(14), boxx("((1 + 1) > 3) ? true && false : 12 + 2"));
    assert_eq!(Expr::Int(14), boxx("1 + 1 > 3 ? true && false : 12 + 2"));
    assert_eq!(
      Expr::Int(10),
      boxx(
          "(false || true) ? ((1 + 2 > 12) ? 9 : 10) : ((1 + 2 < 12) ? 6 : 7)"
       )
    );
    // same as above but without parens
    assert_eq!(
      Expr::Int(10),
      boxx(
          "false || true ? 1 + 2 > 12 ? 9 : 10 : 1 + 2 < 12 ? 6 : 7"
       )
    );

    assert_eq!(Expr::Bool(true), boxx("1 + 2 > (1 == 0 ? 5 : 1)"));

    assert_eq!(Expr::Int(-1), boxx("true;false ? 1;2 : 0;-1"));
  }

  #[test]
  pub fn test_seq() {
    let _ = env_logger::init();
    assert_eq!(Expr::Int(5), boxx("3;5"));
    //assert_eq!(Expr::Int(4), boxx("let x = 3;let y = 1;x + y"));
  }

  #[test]
  pub fn test_mod() {
    assert_eq!(Expr::Int(0), boxx("1 % 1"));
    assert_eq!(Expr::Int(2), boxx("7 % 5"));
    assert_eq!(Expr::Int(3), boxx("-7 % 5"));
    assert_eq!(Expr::Int(-2), boxx("-7 % -5"));
  }

  #[test]
  pub fn test_or_and_and() {
    assert_eq!(Expr::Bool(true), boxx("true && true"));
    assert_eq!(Expr::Bool(false), boxx("false && false"));
    assert_eq!(Expr::Bool(false), boxx("true && false"));
    assert_eq!(Expr::Bool(false), boxx("false && true"));

    assert_eq!(Expr::Bool(true), boxx("true || true"));
    assert_eq!(Expr::Bool(false), boxx("false || false"));
    assert_eq!(Expr::Bool(true), boxx("true || false"));
    assert_eq!(Expr::Bool(true), boxx("false || true"));
  }

  #[test]
  pub fn test_not_and_neg() {
    assert_eq!(Expr::Bool(true), boxx("!false"));

    assert_eq!(Expr::Bool(true), boxx("!(true == false)"));
    assert_eq!(Expr::Bool(true), boxx("!((1 == 1) == (3 <= 2))"));
    assert_eq!(Expr::Bool(false), boxx("!((1 == 1) == !(3 <= 2))"));
    assert_eq!(Expr::Bool(true), boxx("!!(!(!(true)))"));

    assert_eq!(Expr::Int(-1), boxx("-1"));
    assert_eq!(Expr::Int(-100), boxx("-(20 * 5)"));
    assert_eq!(Expr::Int(-100), boxx("-(-20 * -5)"));
    assert_eq!(Expr::Int(-100), boxx("(20 * -5)"));
    assert_eq!(Expr::Int(-100), boxx("(-20 * 5)"));
    assert_eq!(Expr::Int(100), boxx("(-20 * -5)"));
    assert_eq!(Expr::Int(100), boxx("-(20 * -5)"));
    assert_eq!(Expr::Int(100), boxx("-(-20 * 5)"));
    assert_eq!(Expr::Int(0), boxx("1 + -1"));
    assert_eq!(Expr::Int(2), boxx("1 - -1"));
    assert_eq!(Expr::Int(0), boxx("-1 - -1"));
    assert_eq!(Expr::Int(-2), boxx("-1 - 1"));
    assert_eq!(Expr::Int(-2), boxx("-1 * 2"));
    assert_eq!(Expr::Int(-2), boxx("2 * -1"));
    assert_eq!(Expr::Int(-2), boxx("-2 * 1"));
    assert_eq!(Expr::Int(-1), boxx("-(2 * 1) + 1"));
    assert_eq!(Expr::Int(1), boxx("(2 * 1) + -1"));
  }

  #[test]
  pub fn test_comparison_operators() {
    assert_eq!(Expr::Bool(true), boxx("1 == 1"));
    assert_eq!(Expr::Bool(false), boxx("1 == 2"));
    assert_eq!(Expr::Bool(false), boxx("(1 == 1) == (1 == 2)"));
    assert_eq!(Expr::Bool(true), boxx("(5 == 2) == (1 == 2)"));
    assert_eq!(Expr::Bool(true), boxx("(6 == 6) == true"));
    assert_eq!(Expr::Bool(false), boxx("1 == true"));
    assert_eq!(Expr::Bool(true), boxx("false == false"));

    assert_eq!(Expr::Bool(true), boxx("1 > 0"));
    assert_eq!(Expr::Bool(false), boxx("1 < 0"));

    assert_eq!(Expr::Bool(true), boxx("88 > 34"));
    assert_eq!(Expr::Bool(false), boxx("1 < 1"));
    assert_eq!(Expr::Bool(false), boxx("1 > 1"));

    assert_eq!(Expr::Bool(true), boxx("88 != 34"));
    assert_eq!(Expr::Bool(false), boxx("88 != 88"));
    assert_eq!(Expr::Bool(true), boxx("88 <= 88"));
    assert_eq!(Expr::Bool(true), boxx("88 >= 88"));
    assert_eq!(Expr::Bool(true), boxx("1 >= 0"));
    assert_eq!(Expr::Bool(false), boxx("1 >= 12"));

    assert_eq!(Expr::Bool(false), boxx("true != true"));
    assert_eq!(Expr::Bool(true), boxx("true != false"));
  }

  #[test]
  pub fn test_spaces() {
    assert_eq!(Expr::Int(2), boxx("1 + 1"));
    assert_eq!(Expr::Int(12), boxx(" (3+   3)* 2      "));
    assert_eq!(Expr::Int(7), boxx("1 + 3*(3 + (1 - 2))"));
  }

  #[test]
  pub fn test_eval_mult() {
    assert_eq!(Expr::Int(12), boxx("6*2"));
    assert_eq!(Expr::Int(12), boxx("(3+3)*2"));
    assert_eq!(Expr::Int(0), boxx("(3+3)*0"));
  }

  #[test]
  pub fn test_eval_div() {
    assert_eq!(Expr::Int(6), boxx("12/2"));
    //assert_eq!(Expr::Float(1.5), boxx("3/2"));
  }

  #[test]
  pub fn test_eval_addition() {
    assert_eq!(Expr::Int(3), boxx("1+2"));
    assert_eq!(Expr::Int(16), boxx("5+7+4"));
    assert_eq!(Expr::Int(-1), boxx("1-2"));
    assert_eq!(Expr::Int(-100), boxx("32-132"));
    assert_eq!(Expr::Int(-120), boxx("32-132-20"));

    assert_eq!(Expr::Int(-80), boxx("32-(132-20)"));

    assert_eq!(Expr::Int(-6), boxx("4-(7+3)"));
    assert_eq!(Expr::Int(0), boxx("4-(7-3)"));
    assert_eq!(Expr::Int(8), boxx("4+(7-3)"));
    assert_eq!(Expr::Int(8), boxx("(4+7)-3)"));
    assert_eq!(Expr::Int(0), boxx("(4-7)+3)"));
    assert_eq!(Expr::Int(14), boxx("(4+7)+3)"));

    assert_eq!(Expr::Int(2), boxx("(1-1)+(2-2)+(3-3)+((1+2)-((3-2)+1)+1)"));
    assert_eq!(Expr::Int(0), boxx("((((((((((1-1)))+1))))-1)))"));
  }
}
<|endoftext|>


<commit_before>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable, Sizeable, Labelable};
use conrod::color::Colorable;
//use gif::traits::SetParameter;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        // TODO: Remove?
        const FRAME_WIDTH: f64 = 1.;

        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(FRAME_WIDTH)
                .pad(30.)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
//                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .rgb(0.4, 0.75, 0.6)
                .frame(FRAME_WIDTH)
                .label("New game")
                .react(|| ())
                .set(NEW_GAME_BUTTON, ui);

            conrod::Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_GAME_BUTTON, 45.0)
                .rgb(0.4, 0.75, 0.6)
                .frame(FRAME_WIDTH)
                .label("Exit")
                .react(|| ())
                .set(EXIT_BUTTON, ui);
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
    NEW_GAME_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<commit_msg>Comment has been removed<commit_after>use screen::*;
use piston_window;
use conrod::{self, Widget, Frameable, Positionable, Sizeable, Labelable};
use conrod::color::Colorable;

pub struct MainMenuScreen {
    ui: conrod::Ui<piston_window::Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow, context: &mut Context) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window, &context.assets_path) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self,
                input: &piston_window::Input,
                window: &piston_window::PistonWindow,
                context: &mut Context)
                -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window, context))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        self.ui.handle_event(window);
        window.draw_2d(|context, graphics| self.ui.draw_if_changed(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        // TODO: Remove?
        const FRAME_WIDTH: f64 = 1.;

        self.ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(FRAME_WIDTH)
                .pad(30.)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
//                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .rgb(0.4, 0.75, 0.6)
                .frame(FRAME_WIDTH)
                .label("New game")
                .react(|| ())
                .set(NEW_GAME_BUTTON, ui);

            conrod::Button::new()
                .w_h(200.0, 50.0)
                .mid_left_of(CANVAS)
                .down_from(NEW_GAME_BUTTON, 45.0)
                .rgb(0.4, 0.75, 0.6)
                .frame(FRAME_WIDTH)
                .label("Exit")
                .react(|| ())
                .set(EXIT_BUTTON, ui);
        });
    }
}

widget_ids! {
    CANVAS,
    TITLE,
    NEW_GAME_BUTTON,
    EXIT_BUTTON,
}

fn create_ui(window: &piston_window::PistonWindow,
             assets_path: &::std::path::Path)
             -> conrod::Ui<piston_window::Glyphs> {
    let font_path = assets_path.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<|endoftext|>


<commit_before>extern crate time;

use std::io::{BufferedReader, File};
use time::precise_time_ns;

struct Route {
    dest: i32,
    cost: i32,
}

struct Node {
    neighbours: Vec<Route>,
}

fn read_places() -> Vec<Node> {
    let path = Path::new("agraph");
    let mut file = BufferedReader::new(File::open(&path));
    let mut lines = file.lines().map(|x| x.unwrap());

    let numnodes: uint = match lines.next() {
        Some(num) => from_str(num.as_slice().trim()).unwrap(),
        _         => panic!("Error, first line of file should describe the amount of nodes")
    };

    let mut nodes = Vec::from_fn(numnodes, |_| Node { neighbours: Vec::with_capacity(numnodes) });

    for line in lines {
        let nums: Vec<&str> = line.split(' ').collect();
        let node     : uint = from_str(nums[0]       ).expect("Error: node id was not a uint");
        let neighbour: i32  = from_str(nums[1]       ).expect("Error: neighbour id was not an int");
        let cost     : i32  = from_str(nums[2].trim()).expect("Error: route cost was not an int");
        nodes[node].neighbours.push(Route {dest: neighbour, cost: cost});
    }

    return nodes;
}

fn get_longest_path(nodes: &Vec<Node>, node_id: i32, visited: &mut Vec<bool>) -> i32 {
    visited[node_id as uint] = true;
    let mut max = 0i32;

    for neighbour in nodes[node_id as uint].neighbours.iter() {
        if !visited[neighbour.dest as uint] {
            let dist = neighbour.cost + get_longest_path(nodes, neighbour.dest, visited);

            if dist > max {
                max = dist;
            }
        }
    }

    visited[node_id as uint] = false;
    return max;
}

fn main() {
    let nodes = read_places();
    let mut visited = Vec::from_elem(nodes.len(), false);
    let startTime = precise_time_ns();
    let path = get_longest_path(&nodes, 0, &mut visited);
    let duration = (precise_time_ns() - startTime) / 1000000;
    println!("{} LANGUAGE Rust {}", path, duration);
}

<commit_msg>improve rust performance<commit_after>#![feature(slicing_syntax)]
#![allow(deprecated)]

extern crate time;
extern crate test;

use time::{precise_time_ns};
use std::{cmp};

use tree::{Node};

mod tree {
    use std::io::{BufferedReader, File};
    use std::{mem};
    use std::cell::{Cell};

    pub struct Node {
        routes: Box<[(*const Node, i32)]>,
        pub visited: Cell<bool>,
    }

    impl Node {
        pub fn routes(&self) -> &[(&Node, i32)] {
            unsafe { mem::transmute(self.routes[]) }
        }
    }

    pub struct Tree {
        nodes: Box<[Node]>,
    }

    impl Tree {
        pub fn nodes(&self) -> &[Node] {
            self.nodes[]
        }
    }

    pub fn read_places() -> Tree {
        let path = Path::new("agraph");
        let mut file = BufferedReader::new(File::open(&path).unwrap());

        let numnodes = match file.read_line() {
            Ok(num) => num[].trim().parse().unwrap(),
            _ => panic!("Error, first line of file should describe the amount of nodes")
        };

        let mut nodes = Vec::from_fn(numnodes, |_| Node {
            routes: vec!().into_boxed_slice(),
            visited: Cell::new(false),
        }).into_boxed_slice();

        let mut vec_nodes = Vec::from_fn(numnodes, |_| vec!());

        while let Ok(line) = file.read_line() {
            let nums: Vec<&str> = line.trim().split(' ').collect();
            let src  = nums[0].parse().expect("Error: node id was not a uint");
            let dest = nums[1].parse().expect("Error: neighbour id was not an int");
            let cost = nums[2].parse().expect("Error: route cost was not an int");
            vec_nodes[src].push((&nodes[dest] as *const Node, cost));
        }

        for (node, vec_node) in nodes.iter_mut().zip(vec_nodes.into_iter()) {
            node.routes = vec_node.into_boxed_slice();
        }

        Tree { nodes: nodes }
    }
}

fn get_longest_path(nodes: &[Node], cur: &Node) -> i32 {
    let mut max = 0;

    cur.visited.set(true);

    for &(neighbor, cost) in cur.routes().iter() {
        if !neighbor.visited.get() {
            let dist = cost + get_longest_path(nodes, neighbor);
            max = cmp::max(max, dist);
        }
    }

    cur.visited.set(false);

    max
}

fn main() {
    let tree = tree::read_places();
    let start_time = precise_time_ns();
    let path = get_longest_path(tree.nodes(), &tree.nodes()[0]);
    let duration = (precise_time_ns() - start_time) / 1000000;
    println!("{} LANGUAGE Rust {}", path, duration);
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ReaderBytesExt, WriterBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::cell::RefCell;
use std::num::Int;
use std::ops::{Range, Index};
use std::old_io::net;
use std::old_io::net::ip::SocketAddr;
use std::old_io::{TcpStream, MemReader};
use std::old_path::posix::Path;
use std::collections::HashMap;

use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
	pub aps: PayloadAPS<'a>,
	pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
	pub alert: PayloadAPSAlert<'a>,
	pub badge: Option<i32>,
	pub sound: Option<&'a str>,
	pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
	Plain(&'a str),
	Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			Payload{ref aps, ref info} => {
				if let Some(ref map) = *info {
	    	        encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						let mut index = 1usize;
						for (key, val) in map.iter() {
							try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
							index = index + 1;
						}
						Ok(())
	    	        })
				}
				else {
	    	        encoder.emit_struct("Payload", 1, |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						Ok(())
	    	        })
				}
			}
		}
	}
}

impl<'a> Encodable for PayloadAPS<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
				let mut count = 1;
				if badge.is_some() { count = count + 1; }
				if sound.is_some() { count = count + 1; }
				if content_available.is_some() { count = count + 1; }

				let mut index = 0usize;
    	        encoder.emit_struct("PayloadAPS", count, |encoder| {
					try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
					index = index + 1;
					if badge.is_some() {
						try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
						index = index + 1;
					}
					if sound.is_some() {
						try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
						index = index + 1;
					}
					if content_available.is_some() {
						try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
						index = index + 1;
					}
					Ok(())
    	        })
			}
		}
	}
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPSAlert::Plain(ref str) => {
    	        encoder.emit_str(str)
			},
			PayloadAPSAlert::Localized(ref key, ref args) => {
    	        encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
					try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
					try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
					Ok(())
				})
			}
		}
	}
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
	let mut total = 0u32;
	let mut n = hex.to_string().len() - 1;

	for c in hex.chars() {
		match c {
			'0'...'9' => {
				total += 16.pow(n) * ((c as u32) - ('0' as u32));
			},
			'a'...'f' => {
				total += 16.pow(n) * ((c as u32) - ('a' as u32) + 10);
			},
			_ => {
			}
		}
		n = n - 1;
	}

	return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
	let mut device_token_bytes: Vec<u8> = vec![];
	for i in 0..8 {
		let string = device_token.to_string();
		let range = Range{start:i*8, end:i*8+8};
		let sub_str = string.index(&range);

		let sub_str_num = hex_to_int(sub_str);
		let mut sub_str_bytes = vec![];
		let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

		device_token_bytes.push_all(sub_str_bytes.as_slice());
	}

	return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
	let mut token = "".to_string();
	for i in 0..8 {
		let range = Range{start:i*4, end:i*4+4};
		let sub_slice = binary.index(&range);

		let mut rdr = MemReader::new(sub_slice.to_vec());
		let num = rdr.read_u32::<BigEndian>().unwrap();

		token = format!("{}{:x}", token, num);
	}
	return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
	let mut rdr = MemReader::new(binary.to_vec());
	let num = rdr.read_u32::<BigEndian>().unwrap();

	return num;
}

pub struct APNS {
	pub sandbox: bool,
	pub certificate: Path,
	pub private_key: Path,
	pub ca_certificate: Path,
	pub ssl_stream: RefCell<Option<SslStream<TcpStream>>>
}

impl APNS {
	pub fn new(sandbox: bool, cert_file: Path, private_key_file: Path, ca_file: Path) -> APNS {
		APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file, ssl_stream: RefCell::new(None)}
	}

	#[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
		let apns_feedback_production = "feedback.push.apple.com";
		let apns_feedback_development = "feedback.sandbox.push.apple.com";
		let feedback_port = 2196;

		let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
		let mut stream = try!(get_ssl_stream(apns_feedback_url, feedback_port, &self.certificate, &self.private_key, &self.ca_certificate));

		let mut tokens: Vec<(u32, String)> = Vec::new();
        loop {
			let mut read_buffer = [0u8; 38];
			if let Err(..) = stream.read(&mut read_buffer) {
				break;
/*				return Result::Err(SslError::StreamError(error));*/
            }

			let time_range = Range{start:0, end:4};
			let time_slice = read_buffer.index(&time_range);
			let time = convert_to_timestamp(time_slice);

			let token_range = Range{start:6, end:38};
			let token_slice = read_buffer.index(&token_range);
            let token = convert_to_token(token_slice);

			tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

	#[allow(dead_code)]
	pub fn send_payload(&self, payload: Payload, device_token: &str) {
		let payload_str = match json::encode(&payload) {
			Ok(json_str) => { json_str.to_string() }
			_ => { return; }
		};

		let payload_bytes = payload_str.into_bytes();
		let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

		let mut notification_buffer: Vec<u8> = vec![];
		let mut message_buffer: Vec<u8> = vec![];

		// Device token
		let mut device_token_length = vec![];
		let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

		message_buffer.push(1u8);
		message_buffer.push_all(device_token_length.as_slice());
		message_buffer.push_all(device_token_bytes.as_slice());

		// Payload
		let mut payload_length = vec![];
		let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

		message_buffer.push(2u8);
		message_buffer.push_all(payload_length.as_slice());
		message_buffer.push_all(payload_bytes.as_slice());

		// Notification identifier
		let payload_id = rand::thread_rng().gen();
		let mut payload_id_be = vec![];
		let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

		let mut payload_id_length = vec![];
		let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

		message_buffer.push(3u8);
		message_buffer.push_all(payload_id_length.as_slice());
		message_buffer.push_all(payload_id_be.as_slice());

		//	Expiration date
		let time = time::now().to_timespec().sec + 86400;	// expired after one day
		let mut exp_date_be = vec![];
		let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

		let mut exp_date_length = vec![];
		let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

		message_buffer.push(4u8);
		message_buffer.push_all(exp_date_length.as_slice());
		message_buffer.push_all(exp_date_be.as_slice());

		// Priority
		let mut priority_length = vec![];
		let _ = priority_length.write_u16::<BigEndian>(1u16);

		message_buffer.push(5u8);
		message_buffer.push_all(priority_length.as_slice());
		message_buffer.push(10u8);

		let mut message_buffer_length = vec![];
		let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

		let command = 2u8;
		notification_buffer.push(command);
		notification_buffer.push_all(message_buffer_length.as_slice());
		notification_buffer.push_all(message_buffer.as_slice());

		let should_init_ssl_stream = self.ssl_stream.borrow().is_none();

		if should_init_ssl_stream {
			self.init_push_ssl_stream();
		}
		else {
			if let Some(ssl_stream) = self.ssl_stream.borrow_mut().as_mut() {
				while let Err(error) = ssl_stream.write_all(&notification_buffer) {
					println!("ssl_stream write error {:?}", error);
/*		            self.init_push_ssl_stream();*/
				}

				// Response error code
				/*let mut read_buffer = [0u8; 6];
				println!("SslStream read {:?}", ssl_stream.read(&mut read_buffer));

				for c in read_buffer.iter() {
					print!("{}", c);
				}
				println!("");*/
			}
			else {
				println!("ssl_stream wrote successfully. {}", payload_id);
			}
		}
	}

	fn init_push_ssl_stream(&self) {
		let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();

		let apns_url_production = "gateway.push.apple.com";
		let apns_url_development = "gateway.sandbox.push.apple.com";
		let apns_port = 2195;

		let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

		*borrow_ssl_stream = Some(get_ssl_stream(apns_url, apns_port, &self.certificate, &self.private_key, &self.ca_certificate).unwrap());
	}
}

fn get_ssl_stream(url: &str, port: u16, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
	let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

	if let Some(error) = context.set_CA_file(&ca_file) {
		println!("set_CA_file error {:?}", error);
	}
	if let Some(error) = context.set_certificate_file(&cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
	}
	if let Some(error) = context.set_private_key_file(&private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
	}

	let apns_ip = match net::addrinfo::get_host_addresses(url) {
		Ok(results) => { results[0] },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let sock_addr = SocketAddr{ip: apns_ip, port: port};
    let tcp_conn = match TcpStream::connect(sock_addr) {
		Ok(conn) => { conn },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let ssl = try!(ssl::Ssl::new(&context));

	return SslStream::new_from(ssl, tcp_conn);
}

<commit_msg>ssl_stream recreation logic improvements<commit_after>use byteorder::{BigEndian, ReaderBytesExt, WriterBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::cell::RefCell;
use std::num::Int;
use std::ops::{Range, Index};
use std::old_io::net;
use std::old_io::net::ip::SocketAddr;
use std::old_io::{TcpStream, MemReader};
use std::old_path::posix::Path;
use std::collections::HashMap;

use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
	pub aps: PayloadAPS<'a>,
	pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
	pub alert: PayloadAPSAlert<'a>,
	pub badge: Option<i32>,
	pub sound: Option<&'a str>,
	pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
	Plain(&'a str),
	Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			Payload{ref aps, ref info} => {
				if let Some(ref map) = *info {
	    	        encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						let mut index = 1usize;
						for (key, val) in map.iter() {
							try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
							index = index + 1;
						}
						Ok(())
	    	        })
				}
				else {
	    	        encoder.emit_struct("Payload", 1, |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						Ok(())
	    	        })
				}
			}
		}
	}
}

impl<'a> Encodable for PayloadAPS<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
				let mut count = 1;
				if badge.is_some() { count = count + 1; }
				if sound.is_some() { count = count + 1; }
				if content_available.is_some() { count = count + 1; }

				let mut index = 0usize;
    	        encoder.emit_struct("PayloadAPS", count, |encoder| {
					try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
					index = index + 1;
					if badge.is_some() {
						try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
						index = index + 1;
					}
					if sound.is_some() {
						try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
						index = index + 1;
					}
					if content_available.is_some() {
						try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
						index = index + 1;
					}
					Ok(())
    	        })
			}
		}
	}
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPSAlert::Plain(ref str) => {
    	        encoder.emit_str(str)
			},
			PayloadAPSAlert::Localized(ref key, ref args) => {
    	        encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
					try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
					try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
					Ok(())
				})
			}
		}
	}
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
	let mut total = 0u32;
	let mut n = hex.to_string().len() - 1;

	for c in hex.chars() {
		match c {
			'0'...'9' => {
				total += 16.pow(n) * ((c as u32) - ('0' as u32));
			},
			'a'...'f' => {
				total += 16.pow(n) * ((c as u32) - ('a' as u32) + 10);
			},
			_ => {
			}
		}
		n = n - 1;
	}

	return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
	let mut device_token_bytes: Vec<u8> = vec![];
	for i in 0..8 {
		let string = device_token.to_string();
		let range = Range{start:i*8, end:i*8+8};
		let sub_str = string.index(&range);

		let sub_str_num = hex_to_int(sub_str);
		let mut sub_str_bytes = vec![];
		let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

		device_token_bytes.push_all(sub_str_bytes.as_slice());
	}

	return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
	let mut token = "".to_string();
	for i in 0..8 {
		let range = Range{start:i*4, end:i*4+4};
		let sub_slice = binary.index(&range);

		let mut rdr = MemReader::new(sub_slice.to_vec());
		let num = rdr.read_u32::<BigEndian>().unwrap();

		token = format!("{}{:x}", token, num);
	}
	return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
	let mut rdr = MemReader::new(binary.to_vec());
	let num = rdr.read_u32::<BigEndian>().unwrap();

	return num;
}

pub struct APNS {
	pub sandbox: bool,
	pub certificate: Path,
	pub private_key: Path,
	pub ca_certificate: Path,
	pub ssl_stream: RefCell<Option<SslStream<TcpStream>>>
}

impl APNS {
	pub fn new(sandbox: bool, cert_file: Path, private_key_file: Path, ca_file: Path) -> APNS {
		APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file, ssl_stream: RefCell::new(None)}
	}

	#[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
		let apns_feedback_production = "feedback.push.apple.com";
		let apns_feedback_development = "feedback.sandbox.push.apple.com";
		let feedback_port = 2196;

		let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
		let mut stream = try!(get_ssl_stream(apns_feedback_url, feedback_port, &self.certificate, &self.private_key, &self.ca_certificate));

		let mut tokens: Vec<(u32, String)> = Vec::new();
        loop {
			let mut read_buffer = [0u8; 38];
			if let Err(..) = stream.read(&mut read_buffer) {
				break;
/*				return Result::Err(SslError::StreamError(error));*/
            }

			let time_range = Range{start:0, end:4};
			let time_slice = read_buffer.index(&time_range);
			let time = convert_to_timestamp(time_slice);

			let token_range = Range{start:6, end:38};
			let token_slice = read_buffer.index(&token_range);
            let token = convert_to_token(token_slice);

			tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

	#[allow(dead_code)]
	pub fn send_payload(&self, payload: Payload, device_token: &str) {
		let payload_str = match json::encode(&payload) {
			Ok(json_str) => { json_str.to_string() }
			_ => { return; }
		};

		let payload_bytes = payload_str.into_bytes();
		let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

		let mut notification_buffer: Vec<u8> = vec![];
		let mut message_buffer: Vec<u8> = vec![];

		// Device token
		let mut device_token_length = vec![];
		let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

		message_buffer.push(1u8);
		message_buffer.push_all(device_token_length.as_slice());
		message_buffer.push_all(device_token_bytes.as_slice());

		// Payload
		let mut payload_length = vec![];
		let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

		message_buffer.push(2u8);
		message_buffer.push_all(payload_length.as_slice());
		message_buffer.push_all(payload_bytes.as_slice());

		// Notification identifier
		let payload_id = rand::thread_rng().gen();
		let mut payload_id_be = vec![];
		let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

		let mut payload_id_length = vec![];
		let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

		message_buffer.push(3u8);
		message_buffer.push_all(payload_id_length.as_slice());
		message_buffer.push_all(payload_id_be.as_slice());

		//	Expiration date
		let time = time::now().to_timespec().sec + 86400;	// expired after one day
		let mut exp_date_be = vec![];
		let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

		let mut exp_date_length = vec![];
		let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

		message_buffer.push(4u8);
		message_buffer.push_all(exp_date_length.as_slice());
		message_buffer.push_all(exp_date_be.as_slice());

		// Priority
		let mut priority_length = vec![];
		let _ = priority_length.write_u16::<BigEndian>(1u16);

		message_buffer.push(5u8);
		message_buffer.push_all(priority_length.as_slice());
		message_buffer.push(10u8);

		let mut message_buffer_length = vec![];
		let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

		let command = 2u8;
		notification_buffer.push(command);
		notification_buffer.push_all(message_buffer_length.as_slice());
		notification_buffer.push_all(message_buffer.as_slice());

		if self.ssl_stream.borrow().is_none() {
			let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();
			*borrow_ssl_stream = Some(self.init_push_ssl_stream().unwrap());
		}
		else {
			let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();
			let mut retry_count = 3;
			loop {
				if let Some(mut ssl_stream) = borrow_ssl_stream.as_mut() {
					if let Err(error) = ssl_stream.write_all(&notification_buffer) {
						println!("ssl_stream write error {:?}", error);
					}
					else {
						println!("ssl_stream wrote successfully. {}", payload_id);
						break;
					}

					// Response error code
					/*{
						let mut read_buffer = [0u8; 6];
						println!("SslStream read {:?}", ssl_stream.read(&mut read_buffer));

						for c in read_buffer.iter() {
							print!("{}", c);
						}
						println!("");
					}*/
				}

				if retry_count <= 0 { break; }
				retry_count = retry_count - 1;

				*borrow_ssl_stream = Some(self.init_push_ssl_stream().unwrap());
			}
		}
	}

	fn init_push_ssl_stream(&self) -> Result<SslStream<TcpStream>, SslError> {
		let apns_url_production = "gateway.push.apple.com";
		let apns_url_development = "gateway.sandbox.push.apple.com";
		let apns_port = 2195;

		let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

		get_ssl_stream(apns_url, apns_port, &self.certificate, &self.private_key, &self.ca_certificate)
	}
}

fn get_ssl_stream(url: &str, port: u16, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
	let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

	if let Some(error) = context.set_CA_file(&ca_file) {
		println!("set_CA_file error {:?}", error);
	}
	if let Some(error) = context.set_certificate_file(&cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
	}
	if let Some(error) = context.set_private_key_file(&private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
	}

	let apns_ip = match net::addrinfo::get_host_addresses(url) {
		Ok(results) => { results[0] },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let sock_addr = SocketAddr{ip: apns_ip, port: port};
    let tcp_conn = match TcpStream::connect(sock_addr) {
		Ok(conn) => { conn },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let ssl = try!(ssl::Ssl::new(&context));

	return SslStream::new_from(ssl, tcp_conn);
}

<|endoftext|>


<commit_before>extern crate env_logger;
extern crate failure;
extern crate futures;
extern crate glob;
extern crate home;
extern crate hubcaps;
extern crate hyper;
#[macro_use]
extern crate iron;
#[macro_use]
extern crate log;
extern crate mount;
extern crate persistent;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate staticfile;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;
extern crate tokio_core;

extern crate gluon_master;

use std::env;
use std::fs::{read_dir, File};
use std::io::{self, Read};
use std::path::PathBuf;
use std::process::Command;

use regex::Regex;

use iron::mime::Mime;
use iron::modifiers::RedirectRaw;
use iron::prelude::*;
use iron::typemap::Key;
use iron::{status, Handler};

use serde_json::Value;

use staticfile::Static;

use structopt::StructOpt;

use mount::Mount;

mod gluon;

fn format<F, E>(req: &mut Request, format_expr: F) -> IronResult<Response>
where
    F: Fn(&str) -> Result<String, E>,
    E: ::std::fmt::Display,
{
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Format: `{}`", body);
    let mime: Mime = "text/plain".parse().unwrap();
    match format_expr(&body) {
        Ok(formatted) => Ok(Response::with((
            status::Ok,
            mime,
            serde_json::to_string(&formatted).unwrap(),
        ))),
        Err(err) => Ok(Response::with((
            status::NotAcceptable,
            mime,
            serde_json::to_string(&err.to_string()).unwrap(),
        ))),
    }
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Gist {
    pub code: String,
}

#[derive(Debug, Default, Serialize)]
pub struct PostGist<'a> {
    pub id: &'a str,
    pub html_url: &'a str,
}

fn share<C>(
    core: &mut tokio_core::reactor::Core,
    gists: &hubcaps::gists::Gists<C>,
    req: &mut Request,
) -> IronResult<Response>
where
    C: Clone + hyper::client::Connect,
{
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Share: `{}`", body);
    let mime: Mime = "text/plain".parse().unwrap();
    match serde_json::from_str::<Gist>(&body) {
        Ok(gist) => {
            let result = core.run(
                gists.create(&hubcaps::gists::GistOptions {
                    description: Some("Gluon code shared from try_gluon".into()),
                    public: Some(true),
                    files: Some((
                        "try_gluon.glu".into(),
                        hubcaps::gists::Content {
                            filename: None,
                            content: gist.code,
                        },
                    )).into_iter()
                    .collect(),
                }),
            );
            let response = match result {
                Ok(r) => r,
                Err(err) => {
                    error!("{}", err);
                    return Ok(Response::with((status::InternalServerError, mime, "")));
                }
            };

            Ok(Response::with((
                status::Ok,
                mime,
                serde_json::to_string(&PostGist {
                    id: &response.id,
                    html_url: &response.html_url,
                }).unwrap(),
            )))
        }
        Err(err) => Ok(Response::with((
            status::NotAcceptable,
            mime,
            serde_json::to_string(&err.to_string()).unwrap(),
        ))),
    }
}

struct Config;

impl Key for Config {
    type Value = String;
}

fn config(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Config>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

const LOCK_FILE: &str = include_str!("../../Cargo.lock");

fn git_master_version() -> String {
    Regex::new("git\\+[^#]+gluon#([^\"]+)")
        .unwrap()
        .captures(LOCK_FILE)
        .expect("gluon master version")
        .get(1)
        .unwrap()
        .as_str()
        .to_string()
}

fn load_config() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![
                ("name".into(), Value::String(name)),
                ("value".into(), Value::String(contents)),
            ];

            Ok(Value::Object(value.into_iter().collect()))
        }).collect::<io::Result<_>>()
        .unwrap();

    let crates_io_version = Regex::new("checksum gluon ([^ ]+).+registry")
        .unwrap()
        .captures(LOCK_FILE)
        .expect("crates.io version")
        .get(1)
        .unwrap()
        .as_str();
    let git_master_version = git_master_version()[0..6].to_string();

    Value::Object(
        vec![
            (
                "last_release".to_string(),
                Value::String(crates_io_version.to_string()),
            ),
            (
                "git_master".to_string(),
                Value::String(git_master_version.to_string()),
            ),
            ("examples".to_string(), Value::Array(vec)),
        ].into_iter()
        .collect(),
    )
}
fn mount_eval<M>(mount: &mut Mount, prefix: &str, eval: M)
where
    M: Fn(&str) -> IronResult<String> + Send + Sync + 'static,
{
    let middleware = Chain::new(move |req: &mut Request| {
        let mut body = String::new();

        itry!(req.body.read_to_string(&mut body));
        info!("Eval: `{}`", body);

        eval(&body).map(|s| {
            let mime: Mime = "text/plain".parse().unwrap();

            Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
        })
    });

    mount.mount(&format!("{}/eval", prefix), middleware);
}

fn gluon_git_path() -> Result<PathBuf, failure::Error> {
    let std_glob_path = home::cargo_home()?
        .join(&format!(
            "git/checkouts/gluon-*/{}",
            &git_master_version()[..7]
        )).display()
        .to_string();
    Ok(glob::glob(&std_glob_path)?
        .next()
        .expect("git repo in cargo home")?)
}

fn create_docs(path: &str) -> Result<(), failure::Error> {
    let git_dir = gluon_git_path()?;

    let exit_status = Command::new("cp")
        .args(&["-r", &git_dir.join("std").to_string_lossy(), "std"])
        .status()?;
    if !exit_status.success() {
        return Err(failure::err_msg("Error copying docs"));
    }

    gluon_master::generate_doc("std", path)?;

    let mut command = Command::new("mdbook");
    command.args(&[
        "build",
        "--dest-dir",
        &env::current_dir()?.join("dist/book").to_string_lossy(),
        &git_dir.join("book").to_string_lossy(),
    ]);
    println!("Building book: {:?}", command);
    let exit_status = command.status()?;
    if !exit_status.success() {
        return Err(failure::err_msg("Error building book docs"));
    }

    Ok(())
}

#[derive(StructOpt)]
struct Opts {
    #[structopt(
        long = "gist-access-token",
        env = "GIST_ACCESS_TOKEN",
        help = "The access tokens used to create gists"
    )]
    gist_access_token: Option<String>,
}

fn main() {
    if let Err(err) = main_() {
        eprintln!("{}\n{}", err, err.backtrace());
    }
}

fn main_() -> Result<(), failure::Error> {
    env_logger::init();

    let opts = Opts::from_args();

    let try_mount = {
        let mut try_mount = Mount::new();

        try_mount.mount("/", Static::new("dist/try"));

        {
            let mut middleware = Chain::new(config);
            let config_string = serde_json::to_string(&load_config()).unwrap();

            middleware.link(persistent::Read::<Config>::both(config_string));
            try_mount.mount("/config", middleware);
        }

        {
            let vm = gluon::make_eval_vm();
            {
                let vm = vm.clone();
                mount_eval(&mut try_mount, "", move |body| {
                    Ok(match gluon::eval(&vm, body) {
                        Ok(x) => x,
                        Err(err) => err.to_string(),
                    })
                });
            }

            try_mount.mount("/format", move |req: &mut Request| {
                format(req, |input| gluon::format_expr(&vm, input))
            });
        }

        {
            let vm = gluon_master::make_eval_vm();
            {
                let vm = vm.clone();
                mount_eval(&mut try_mount, "/master", move |body| {
                    Ok(match gluon_master::eval(&vm, body) {
                        Ok(x) => x,
                        Err(err) => err.to_string(),
                    })
                });
            }

            try_mount.mount("/master/format", move |req: &mut Request| {
                format(req, |input| gluon_master::format_expr(&vm, input))
            });
        }

        if let Some(gist_access_token) = opts.gist_access_token {
            try_mount.mount("/share", move |req: &mut Request| {
                let mut core = tokio_core::reactor::Core::new().unwrap();
                let github = hubcaps::Github::new(
                    "try_gluon".to_string(),
                    hubcaps::Credentials::Token(gist_access_token.clone()),
                    &core.handle(),
                );

                share(&mut core, &github.gists(), req)
            });
        } else {
            warn!("Gist sharing is not enabled!");
            try_mount.mount("/share", |_: &mut Request| {
                Ok(Response::with((
                    status::InternalServerError,
                    "Gist sharing is not enabled!",
                )))
            });
        }

        try_mount
    };

    let mut mount = Mount::new();
    mount.mount("/try/", try_mount);
    mount.mount("/", Static::new("dist"));

    let doc_path = "dist/doc/nightly";
    create_docs(doc_path)?;
    mount.mount("doc/nightly", Static::new(doc_path));
    mount.mount("book", Static::new("dist/book"));

    let address = "0.0.0.0:8080";
    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(move |req: &mut Request| {
        // Redirect `try` to `try/` to make relative paths work
        // Need to hack it in here since `Mount` strips trailing `/` ...
        if req.url.path() == ["try"] {
            Ok(Response::with((
                status::PermanentRedirect,
                RedirectRaw(format!(
                    "/try/{}",
                    req.url
                        .query()
                        .map(|q| format!("?{}", q))
                        .unwrap_or(String::new())
                )),
            )))
        } else {
            mount.handle(req)
        }
    }).http(address)?;

    println!("Server started at `{}`", address);
    Ok(())
}
<commit_msg>Handle patch in Cargo.toml<commit_after>extern crate env_logger;
extern crate failure;
extern crate futures;
extern crate glob;
extern crate home;
extern crate hubcaps;
extern crate hyper;
#[macro_use]
extern crate iron;
#[macro_use]
extern crate log;
extern crate mount;
extern crate persistent;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate staticfile;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;
extern crate tokio_core;

extern crate gluon_master;

use std::env;
use std::fs::{read_dir, File};
use std::io::{self, Read};
use std::path::PathBuf;
use std::process::Command;

use regex::Regex;

use iron::mime::Mime;
use iron::modifiers::RedirectRaw;
use iron::prelude::*;
use iron::typemap::Key;
use iron::{status, Handler};

use serde_json::Value;

use staticfile::Static;

use structopt::StructOpt;

use mount::Mount;

mod gluon;

fn format<F, E>(req: &mut Request, format_expr: F) -> IronResult<Response>
where
    F: Fn(&str) -> Result<String, E>,
    E: ::std::fmt::Display,
{
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Format: `{}`", body);
    let mime: Mime = "text/plain".parse().unwrap();
    match format_expr(&body) {
        Ok(formatted) => Ok(Response::with((
            status::Ok,
            mime,
            serde_json::to_string(&formatted).unwrap(),
        ))),
        Err(err) => Ok(Response::with((
            status::NotAcceptable,
            mime,
            serde_json::to_string(&err.to_string()).unwrap(),
        ))),
    }
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Gist {
    pub code: String,
}

#[derive(Debug, Default, Serialize)]
pub struct PostGist<'a> {
    pub id: &'a str,
    pub html_url: &'a str,
}

fn share<C>(
    core: &mut tokio_core::reactor::Core,
    gists: &hubcaps::gists::Gists<C>,
    req: &mut Request,
) -> IronResult<Response>
where
    C: Clone + hyper::client::Connect,
{
    let mut body = String::new();

    itry!(req.body.read_to_string(&mut body));
    info!("Share: `{}`", body);
    let mime: Mime = "text/plain".parse().unwrap();
    match serde_json::from_str::<Gist>(&body) {
        Ok(gist) => {
            let result = core.run(
                gists.create(&hubcaps::gists::GistOptions {
                    description: Some("Gluon code shared from try_gluon".into()),
                    public: Some(true),
                    files: Some((
                        "try_gluon.glu".into(),
                        hubcaps::gists::Content {
                            filename: None,
                            content: gist.code,
                        },
                    )).into_iter()
                    .collect(),
                }),
            );
            let response = match result {
                Ok(r) => r,
                Err(err) => {
                    error!("{}", err);
                    return Ok(Response::with((status::InternalServerError, mime, "")));
                }
            };

            Ok(Response::with((
                status::Ok,
                mime,
                serde_json::to_string(&PostGist {
                    id: &response.id,
                    html_url: &response.html_url,
                }).unwrap(),
            )))
        }
        Err(err) => Ok(Response::with((
            status::NotAcceptable,
            mime,
            serde_json::to_string(&err.to_string()).unwrap(),
        ))),
    }
}

struct Config;

impl Key for Config {
    type Value = String;
}

fn config(req: &mut Request) -> IronResult<Response> {
    let s = req.get::<persistent::Read<Config>>().unwrap();
    Ok(Response::with((status::Ok, (*s).clone())))
}

const LOCK_FILE: &str = include_str!("../../Cargo.lock");

fn git_master_version() -> String {
    Regex::new("git\\+[^#]+gluon#([^\"]+)")
        .unwrap()
        .captures(LOCK_FILE)
        .expect("gluon master version")
        .get(1)
        .unwrap()
        .as_str()
        .to_string()
}

fn load_config() -> Value {
    let vec = read_dir("public/examples")
        .unwrap()
        .map(|entry| {
            let path = try!(entry).path();
            let name = String::from(path.file_stem().unwrap().to_str().unwrap());
            let mut file = try!(File::open(path));
            let mut contents = String::new();

            try!(file.read_to_string(&mut contents));

            let value = vec![
                ("name".into(), Value::String(name)),
                ("value".into(), Value::String(contents)),
            ];

            Ok(Value::Object(value.into_iter().collect()))
        }).collect::<io::Result<_>>()
        .unwrap();

    let crates_io_version = Regex::new("checksum gluon ([^ ]+).+(registry|git)")
        .unwrap()
        .captures(LOCK_FILE)
        .expect("crates.io version")
        .get(1)
        .unwrap()
        .as_str();
    let git_master_version = git_master_version()[0..6].to_string();

    Value::Object(
        vec![
            (
                "last_release".to_string(),
                Value::String(crates_io_version.to_string()),
            ),
            (
                "git_master".to_string(),
                Value::String(git_master_version.to_string()),
            ),
            ("examples".to_string(), Value::Array(vec)),
        ].into_iter()
        .collect(),
    )
}
fn mount_eval<M>(mount: &mut Mount, prefix: &str, eval: M)
where
    M: Fn(&str) -> IronResult<String> + Send + Sync + 'static,
{
    let middleware = Chain::new(move |req: &mut Request| {
        let mut body = String::new();

        itry!(req.body.read_to_string(&mut body));
        info!("Eval: `{}`", body);

        eval(&body).map(|s| {
            let mime: Mime = "text/plain".parse().unwrap();

            Response::with((status::Ok, mime, serde_json::to_string(&s).unwrap()))
        })
    });

    mount.mount(&format!("{}/eval", prefix), middleware);
}

fn gluon_git_path() -> Result<PathBuf, failure::Error> {
    let std_glob_path = home::cargo_home()?
        .join(&format!(
            "git/checkouts/gluon-*/{}",
            &git_master_version()[..7]
        )).display()
        .to_string();
    Ok(glob::glob(&std_glob_path)?
        .next()
        .expect("git repo in cargo home")?)
}

fn create_docs(path: &str) -> Result<(), failure::Error> {
    let git_dir = gluon_git_path()?;

    let exit_status = Command::new("cp")
        .args(&["-r", &git_dir.join("std").to_string_lossy(), "std"])
        .status()?;
    if !exit_status.success() {
        return Err(failure::err_msg("Error copying docs"));
    }

    gluon_master::generate_doc("std", path)?;

    let mut command = Command::new("mdbook");
    command.args(&[
        "build",
        "--dest-dir",
        &env::current_dir()?.join("dist/book").to_string_lossy(),
        &git_dir.join("book").to_string_lossy(),
    ]);
    println!("Building book: {:?}", command);
    let exit_status = command.status()?;
    if !exit_status.success() {
        return Err(failure::err_msg("Error building book docs"));
    }

    Ok(())
}

#[derive(StructOpt)]
struct Opts {
    #[structopt(
        long = "gist-access-token",
        env = "GIST_ACCESS_TOKEN",
        help = "The access tokens used to create gists"
    )]
    gist_access_token: Option<String>,
}

fn main() {
    if let Err(err) = main_() {
        eprintln!("{}\n{}", err, err.backtrace());
    }
}

fn main_() -> Result<(), failure::Error> {
    env_logger::init();

    let opts = Opts::from_args();

    let try_mount = {
        let mut try_mount = Mount::new();

        try_mount.mount("/", Static::new("dist/try"));

        {
            let mut middleware = Chain::new(config);
            let config_string = serde_json::to_string(&load_config()).unwrap();

            middleware.link(persistent::Read::<Config>::both(config_string));
            try_mount.mount("/config", middleware);
        }

        {
            let vm = gluon::make_eval_vm();
            {
                let vm = vm.clone();
                mount_eval(&mut try_mount, "", move |body| {
                    Ok(match gluon::eval(&vm, body) {
                        Ok(x) => x,
                        Err(err) => err.to_string(),
                    })
                });
            }

            try_mount.mount("/format", move |req: &mut Request| {
                format(req, |input| gluon::format_expr(&vm, input))
            });
        }

        {
            let vm = gluon_master::make_eval_vm();
            {
                let vm = vm.clone();
                mount_eval(&mut try_mount, "/master", move |body| {
                    Ok(match gluon_master::eval(&vm, body) {
                        Ok(x) => x,
                        Err(err) => err.to_string(),
                    })
                });
            }

            try_mount.mount("/master/format", move |req: &mut Request| {
                format(req, |input| gluon_master::format_expr(&vm, input))
            });
        }

        if let Some(gist_access_token) = opts.gist_access_token {
            try_mount.mount("/share", move |req: &mut Request| {
                let mut core = tokio_core::reactor::Core::new().unwrap();
                let github = hubcaps::Github::new(
                    "try_gluon".to_string(),
                    hubcaps::Credentials::Token(gist_access_token.clone()),
                    &core.handle(),
                );

                share(&mut core, &github.gists(), req)
            });
        } else {
            warn!("Gist sharing is not enabled!");
            try_mount.mount("/share", |_: &mut Request| {
                Ok(Response::with((
                    status::InternalServerError,
                    "Gist sharing is not enabled!",
                )))
            });
        }

        try_mount
    };

    let mut mount = Mount::new();
    mount.mount("/try/", try_mount);
    mount.mount("/", Static::new("dist"));

    let doc_path = "dist/doc/nightly";
    create_docs(doc_path)?;
    mount.mount("doc/nightly", Static::new(doc_path));
    mount.mount("book", Static::new("dist/book"));

    let address = "0.0.0.0:8080";
    // Dropping `server` causes it to block so keep it alive until the end of scope
    let _server = Iron::new(move |req: &mut Request| {
        // Redirect `try` to `try/` to make relative paths work
        // Need to hack it in here since `Mount` strips trailing `/` ...
        if req.url.path() == ["try"] {
            Ok(Response::with((
                status::PermanentRedirect,
                RedirectRaw(format!(
                    "/try/{}",
                    req.url
                        .query()
                        .map(|q| format!("?{}", q))
                        .unwrap_or(String::new())
                )),
            )))
        } else {
            mount.handle(req)
        }
    }).http(address)?;

    println!("Server started at `{}`", address);
    Ok(())
}
<|endoftext|>