<commit_before>pub fn compare(a: &str, b: &str) -> bool {
    encode_compare(a) == encode_compare(b)
}

pub fn encode_compare(s: &str) -> String {
    if s.len() == 0 {
        return "".to_string();
    }

    let first_char = s.to_lowercase().chars().nth(0).unwrap();
    let mut v : Vec<u8> = s[1..].to_lowercase().chars().map(|x|
            match x {
                'b' | 'f' | 'p' | 'v' => '1',
                'c' | 'g' | 'j' | 'k' | 'q' | 's' | 'x' | 'z' => '2',
                'd' | 't' => '3',
                'l' => '4',
                'm' | 'n' => '5' ,
                'r' => '6',
                _ => ' ',
            }
        ).filter(|x| *x != ' ').map(|x|
            x as u8
        ).collect();

    v.dedup();

    let digits = String::from_utf8(v).unwrap();
    match digits.len() {
        0...2 => format!("{}{digits:>width$}", first_char, digits=digits, width=3).replace(" ","0"),
        3 => format!("{}{}", first_char, digits),
        _ => format!("{}{}", first_char, &digits[..2]),
    }
}

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

    #[test]
    fn compare_empty() {
        assert!(compare("", ""));
    }

    #[test]
    fn compare_eq_small() {
        assert!(compare("x", "x"));
    }

    #[test]
    fn compare_ne_small() {
        assert!(!compare("x", "y"));
    }

    #[test]
    fn compare_eq_large() {
        assert!(compare("alphabet", "alphabet"));
    }

    #[test]
    fn compare_ne_large() {
        assert!(compare("alphabet", "alphabte"));
    }
}
<commit_msg>changed function name for soundex encoding.<commit_after>pub fn compare(a: &str, b: &str) -> bool {
    encode_soundex(a) == encode_soundex(b)
}

pub fn encode_soundex(s: &str) -> String {
    if s.len() == 0 {
        return "".to_string();
    }

    let first_char = s.to_lowercase().chars().nth(0).unwrap();
    let mut v : Vec<u8> = s[1..].to_lowercase().chars().map(|x|
            match x {
                'b' | 'f' | 'p' | 'v' => '1',
                'c' | 'g' | 'j' | 'k' | 'q' | 's' | 'x' | 'z' => '2',
                'd' | 't' => '3',
                'l' => '4',
                'm' | 'n' => '5' ,
                'r' => '6',
                _ => ' ',
            }
        ).filter(|x| *x != ' ').map(|x|
            x as u8
        ).collect();

    v.dedup();

    let digits = String::from_utf8(v).unwrap();
    match digits.len() {
        0...2 => format!("{}{digits:>width$}", first_char, digits=digits, width=3).replace(" ","0"),
        3 => format!("{}{}", first_char, digits),
        _ => format!("{}{}", first_char, &digits[..2]),
    }
}

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

    #[test]
    fn compare_empty() {
        assert!(compare("", ""));
    }

    #[test]
    fn compare_eq_small() {
        assert!(compare("x", "x"));
    }

    #[test]
    fn compare_ne_small() {
        assert!(!compare("x", "y"));
    }

    #[test]
    fn compare_eq_large() {
        assert!(compare("alphabet", "alphabet"));
    }

    #[test]
    fn compare_ne_large() {
        assert!(compare("alphabet", "alphabte"));
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::BTreeMap;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;

static BASE_URL: &'static str = "https://api.spotify.com/v1";

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Track {
    pub album:             Album,
    pub artists:           Vec<Artist>,
    pub available_markets: Vec<String>,
    pub disc_number:       i32,
    pub duration_ms:       i32,
    pub explicit:          bool,
    pub external_ids:      BTreeMap<String, String>,
    pub external_urls:     BTreeMap<String, String>,
    pub href:              String,
    pub id:                String,
    pub is_playable:       Option<bool>,
    pub linked_from:       Option<TrackLink>,
    pub name:              String,
    pub popularity:        i32,
    pub preview_url:       String,
    pub track_number:      i32,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:               String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Album {
    pub album_type: String,
    pub artists:    Vec<Artist>,
    pub available_markets: Vec<String>,
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub images:        Vec<Image>,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Artist {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Image {
    pub height: i32,
    pub url:    String,
    pub width:  i32,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct TrackLink {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

/// This function fetches a track info with spotify api.
///
/// # Examples
///
/// ```
/// let track = pink_spider::spotify::fetch_track("3n3Ppam7vgaVa1iaRUc9Lp").unwrap();
///
/// assert_eq!(track.id, "3n3Ppam7vgaVa1iaRUc9Lp");
/// ```
pub fn fetch_track(id: &str) -> json::DecodeResult<Track> {
    let url    = format!("{}/tracks/{}", BASE_URL, id);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    json::decode::<Track>(&body)
}
<commit_msg>Add spotify playlist and related struct<commit_after>use std::io::Read;
use std::collections::BTreeMap;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;

static BASE_URL: &'static str = "https://api.spotify.com/v1";

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Track {
    pub album:             Album,
    pub artists:           Vec<Artist>,
    pub available_markets: Vec<String>,
    pub disc_number:       i32,
    pub duration_ms:       i32,
    pub explicit:          bool,
    pub external_ids:      BTreeMap<String, String>,
    pub external_urls:     BTreeMap<String, String>,
    pub href:              String,
    pub id:                String,
    pub is_playable:       Option<bool>,
    pub linked_from:       Option<TrackLink>,
    pub name:              String,
    pub popularity:        i32,
    pub preview_url:       String,
    pub track_number:      i32,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:               String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Playlist {
    pub collaborative: bool,
    pub description:   Option<String>,
    pub external_urls: BTreeMap<String, String>,
    pub followers:     Followers,
    pub href:          Option<String>,
    pub id:            String,
    pub images:        Vec<Image>,
    pub name:          String,
    pub owner:         User,
    pub public:        Option<bool>,
    pub snapshot_id:   String,
    pub tracks:        PagingObject<PlaylistTrack>,
//  pub type           String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct User {
    pub display_name:  Option<String>,
    pub external_urls: BTreeMap<String, String>,
    pub followers:     Option<Followers>,
    pub href:          String,
    pub id:            String,
    pub images:        Option<Vec<Image>>,
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Album {
    pub album_type: String,
    pub artists:    Vec<Artist>,
    pub available_markets: Vec<String>,
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub images:        Vec<Image>,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Artist {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
    pub name:          String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Image {
    pub height: Option<i32>,
    pub url:    String,
    pub width:  Option<i32>,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct TrackLink {
    pub external_urls: BTreeMap<String, String>,
    pub href:          String,
    pub id:            String,
//  pub type:            String, TODO Use serde instead of rustc_serialize
    pub uri:           String,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Followers {
    pub href:  Option<String>,
    pub total: i32,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct PlaylistTrack {
    pub added_at: String,
    pub added_by: User,
    pub is_local: bool,
    pub track:    Track,
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct PagingObject<T> {
    pub href:     String,
    pub items:    Vec<T>,
    pub limit:    i32,
    pub next:     Option<String>,
    pub offset:   i32,
    pub previous: Option<String>,
    pub total:    i32,
}

/// This function fetches a track info with spotify api.
///
/// # Examples
///
/// ```
/// let track = pink_spider::spotify::fetch_track("3n3Ppam7vgaVa1iaRUc9Lp").unwrap();
///
/// assert_eq!(track.id, "3n3Ppam7vgaVa1iaRUc9Lp");
/// ```
pub fn fetch_track(id: &str) -> json::DecodeResult<Track> {
    let url    = format!("{}/tracks/{}", BASE_URL, id);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    json::decode::<Track>(&body)
}
<|endoftext|>


<commit_before>// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` are enabled.
// `while` loops require `#![feature(const_if_match)]` to be enabled as well.

// gate-test-const_loop
// revisions: stock if_match loop_ both

#![cfg_attr(any(both, if_match), feature(const_if_match))]
#![cfg_attr(any(both, loop_), feature(const_loop))]

const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`

static FOO: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `static`

const fn foo() {
    loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
}

pub trait Foo {
    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
}

impl Foo for () {
    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
}

fn non_const_outside() {
    const fn const_inside() {
        loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
    }
}

const fn const_outside() {
    fn non_const_inside() {
        loop {}
    }
}

fn main() {
    let x = [0; {
        while false {}
        //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const`
        4
    }];
}

const _: i32 = {
    let mut x = 0;

    while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
        x += 1;
    }

    while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
        x += 1;
    }

    x
};

const _: i32 = {
    let mut x = 0;

    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
        x += i;
    }

    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
        x += i;
    }

    x
};

const _: i32 = {
    let mut x = 0;

    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
        x += 1;
        if x == 4 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
            break;
        }
    }

    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
        x += 1;
        if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
            break;
        }
    }

    x
};

const _: i32 = {
    let mut x = 0;
    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
    x
};
<commit_msg>Fix grammar in test description<commit_after>// Ensure that loops are forbidden in a const context unless `#![feature(const_loop)]` is enabled.
// `while` loops require `#![feature(const_if_match)]` to be enabled as well.

// gate-test-const_loop
// revisions: stock if_match loop_ both

#![cfg_attr(any(both, if_match), feature(const_if_match))]
#![cfg_attr(any(both, loop_), feature(const_loop))]

const _: () = loop {}; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`

static FOO: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `static`

const fn foo() {
    loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
}

pub trait Foo {
    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
}

impl Foo for () {
    const BAR: i32 = loop { break 4; }; //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
}

fn non_const_outside() {
    const fn const_inside() {
        loop {} //[stock,if_match]~ ERROR `loop` is not allowed in a `const fn`
    }
}

const fn const_outside() {
    fn non_const_inside() {
        loop {}
    }
}

fn main() {
    let x = [0; {
        while false {}
        //[stock,if_match,loop_]~^ ERROR `while` is not allowed in a `const`
        4
    }];
}

const _: i32 = {
    let mut x = 0;

    while x < 4 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
        x += 1;
    }

    while x < 8 { //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
        x += 1;
    }

    x
};

const _: i32 = {
    let mut x = 0;

    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
        x += i;
    }

    for i in 0..4 { //[stock,if_match,loop_,both]~ ERROR `for` is not allowed in a `const`
        x += i;
    }

    x
};

const _: i32 = {
    let mut x = 0;

    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
        x += 1;
        if x == 4 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
            break;
        }
    }

    loop { //[stock,if_match]~ ERROR `loop` is not allowed in a `const`
        x += 1;
        if x == 8 { //[stock,loop_]~ ERROR `if` is not allowed in a `const`
            break;
        }
    }

    x
};

const _: i32 = {
    let mut x = 0;
    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
    while let None = Some(x) { } //[stock,if_match,loop_]~ ERROR `while` is not allowed in a `const`
    x
};
<|endoftext|>


<commit_before>pub mod human;
pub mod ki;

use arena;
use db::pokemon_token::PokemonToken;
use db::pokedex::*;
use db::{enums, moves};

/// The Player type represents if the Player is a Human or a specific Ai to call different funcions
/// for e.g. choosing Pokemon
#[derive(Clone, Debug)]
pub enum PlayerType {
    Human,
    SimpleAi,
}

/// The Player struct represents a Player and holds his Type (Human, Ai...), a list of his pokemon,
/// the amount of pokemon, his currently fighting pokemon and the next_move he wants to make
#[derive(Clone, Debug)]
pub struct Player {
    player: PlayerType,
    pokemon_list: Vec<PokemonToken>,
    pokemon_count: usize,
    current: usize,
    next_move: Option<(moves::Technique, u8)>,
    last_move: Option<(moves::Technique, AttackSlot)>,
}

impl Player {
    // Constuctor
    //
    /// Takes an array with pokemon id´s and the PlayerType and returns a player
    pub fn new_by_id(input: &[usize], player_type: PlayerType) -> Self {
        let mut pokemon = Vec::new();
        let len = input.len();
        let dex = Pokedex::new();
        for i in 0..input.len() {
            pokemon.push(PokemonToken::from_model(dex.pokemon_by_id(input[i]).unwrap()));
        }
        Player {
            player: player_type,
            pokemon_list: pokemon,
            pokemon_count: len,
            current: 0,
            next_move: None,
            last_move: None,
        }
    }

    // Getter methods
    //
    /// Returns the list of pokemon choosen by the player
    pub fn get_pokemon_list(&mut self) -> &mut Vec<PokemonToken> {
        &mut self.pokemon_list
    }
    /// Returns the currently fighting pokemon
    pub fn get_current(&self) -> usize {
        self.current
    }
    /// Gets the amount of pokemon choosen by the player
    pub fn get_pokemon_count(&self) -> usize {
        self.pokemon_count
    }
    /// Returns the amount of pokemon with atleast one hp
    pub fn get_alive_count(&mut self) -> usize {
        // self.pokemon_list.iter().filter(|x| x.get_current().get_stat(enums::Stats::Hp) != 0)
        //     .count()
        3
    }
    /// Returns a Vec with the id´s from the pokemon which are alive
    pub fn get_alive_list(&self) -> Vec<usize> {
        let mut vec = Vec::new();
        // for i in 0..self.pokemon_list.len() {
        //     if self.get_pokemon_list()[i].get_current().get_stat(enums::Stats::Hp) != 0 {
        //         vec.push(i);
        //     }
        // }
        vec
    }
    /// Gets a attack saved in an attackslot
    pub fn get_attack(&mut self, slot: &AttackSlot) -> moves::Technique {
        match slot {
            &AttackSlot::One => self.pokemon_list[self.current].clone().get_move_one().unwrap(),
            &AttackSlot::Two => self.pokemon_list[self.current].clone().get_move_two().unwrap(),
            &AttackSlot::Three => self.pokemon_list[self.current].clone().get_move_three().unwrap(),
            &AttackSlot::Four => self.pokemon_list[self.current].clone().get_move_four().unwrap(),
        }
    }
    /// Gets the next attack from the Player. Returns none if no Technique is selected
    pub fn get_next_move(&self) -> Option<(moves::Technique, u8)> {
        self.next_move.clone()
    }
    /// Gets the last move with the Slot. Returns None if the last move wasn´t an attack
    pub fn get_last_move(&self) -> Option<(moves::Technique, AttackSlot)> {
        self.last_move.clone()
    }

    // Setter methods
    //
    /// Sets the current value (e.g. after a pokemon swap)
    /// Given values should be between 1 and the maximum amount of pokemon you have
    pub fn set_current(&mut self, new: usize) {
        self.current = new;
    }
    /// Sets a next move to the Player
    pub fn set_next_move(&mut self, next: Option<(moves::Technique, u8)>) {
        self.next_move = next;
    }
    /// Sets the last move the attacking pokemon made with the Slot in which it is saved
    pub fn set_last_move(&mut self, last: Option<(moves::Technique, AttackSlot)>) {
        self.last_move = last;
    }
    // Other
    //
    pub fn attack_or_swap(&self) -> arena::to_ui::Move {
        match self.player {
            PlayerType::Human => arena::to_ui::ui_move(),
            PlayerType::SimpleAi => arena::to_ui::ui_move(),
        }
    }
}

/// An enum which represents the AttackSlot to match with it
#[derive(Debug, Clone)]
pub enum AttackSlot {
    One,
    Two,
    Three,
    Four,
}
<commit_msg>fix for travis<commit_after>pub mod human;
pub mod ki;

use arena;
use db::pokemon_token::PokemonToken;
use db::pokedex::*;
use db::moves;

/// The Player type represents if the Player is a Human or a specific Ai to call different funcions
/// for e.g. choosing Pokemon
#[derive(Clone, Debug)]
pub enum PlayerType {
    Human,
    SimpleAi,
}

/// The Player struct represents a Player and holds his Type (Human, Ai...), a list of his pokemon,
/// the amount of pokemon, his currently fighting pokemon and the next_move he wants to make
#[derive(Clone, Debug)]
pub struct Player {
    player: PlayerType,
    pokemon_list: Vec<PokemonToken>,
    pokemon_count: usize,
    current: usize,
    next_move: Option<(moves::Technique, u8)>,
    last_move: Option<(moves::Technique, AttackSlot)>,
}

impl Player {
    // Constuctor
    //
    /// Takes an array with pokemon id´s and the PlayerType and returns a player
    pub fn new_by_id(input: &[usize], player_type: PlayerType) -> Self {
        let mut pokemon = Vec::new();
        let len = input.len();
        let dex = Pokedex::new();
        for i in 0..input.len() {
            pokemon.push(PokemonToken::from_model(dex.pokemon_by_id(input[i]).unwrap()));
        }
        Player {
            player: player_type,
            pokemon_list: pokemon,
            pokemon_count: len,
            current: 0,
            next_move: None,
            last_move: None,
        }
    }

    // Getter methods
    //
    /// Returns the list of pokemon choosen by the player
    pub fn get_pokemon_list(&mut self) -> &mut Vec<PokemonToken> {
        &mut self.pokemon_list
    }
    /// Returns the currently fighting pokemon
    pub fn get_current(&self) -> usize {
        self.current
    }
    /// Gets the amount of pokemon choosen by the player
    pub fn get_pokemon_count(&self) -> usize {
        self.pokemon_count
    }
    /// Returns the amount of pokemon with atleast one hp
    pub fn get_alive_count(&mut self) -> usize {
        // self.pokemon_list.iter().filter(|x| x.get_current().get_stat(enums::Stats::Hp) != 0)
        //     .count()
        3
    }
    /// Returns a Vec with the id´s from the pokemon which are alive
    pub fn get_alive_list(&self) -> Vec<usize> {
        let vec = Vec::new();
        // for i in 0..self.pokemon_list.len() {
        //     if self.get_pokemon_list()[i].get_current().get_stat(enums::Stats::Hp) != 0 {
        //         vec.push(i);
        //     }
        // }
        vec
    }
    /// Gets a attack saved in an attackslot
    pub fn get_attack(&mut self, slot: &AttackSlot) -> moves::Technique {
        match slot {
            &AttackSlot::One => self.pokemon_list[self.current].clone().get_move_one().unwrap(),
            &AttackSlot::Two => self.pokemon_list[self.current].clone().get_move_two().unwrap(),
            &AttackSlot::Three => self.pokemon_list[self.current].clone().get_move_three().unwrap(),
            &AttackSlot::Four => self.pokemon_list[self.current].clone().get_move_four().unwrap(),
        }
    }
    /// Gets the next attack from the Player. Returns none if no Technique is selected
    pub fn get_next_move(&self) -> Option<(moves::Technique, u8)> {
        self.next_move.clone()
    }
    /// Gets the last move with the Slot. Returns None if the last move wasn´t an attack
    pub fn get_last_move(&self) -> Option<(moves::Technique, AttackSlot)> {
        self.last_move.clone()
    }

    // Setter methods
    //
    /// Sets the current value (e.g. after a pokemon swap)
    /// Given values should be between 1 and the maximum amount of pokemon you have
    pub fn set_current(&mut self, new: usize) {
        self.current = new;
    }
    /// Sets a next move to the Player
    pub fn set_next_move(&mut self, next: Option<(moves::Technique, u8)>) {
        self.next_move = next;
    }
    /// Sets the last move the attacking pokemon made with the Slot in which it is saved
    pub fn set_last_move(&mut self, last: Option<(moves::Technique, AttackSlot)>) {
        self.last_move = last;
    }
    // Other
    //
    pub fn attack_or_swap(&self) -> arena::to_ui::Move {
        match self.player {
            PlayerType::Human => arena::to_ui::ui_move(),
            PlayerType::SimpleAi => arena::to_ui::ui_move(),
        }
    }
}

/// An enum which represents the AttackSlot to match with it
#[derive(Debug, Clone)]
pub enum AttackSlot {
    One,
    Two,
    Three,
    Four,
}
<|endoftext|>


<commit_before>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `Variant` binding and helper traits.
//!
//! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic
//! container. Its type and value are defined at construction and never change.
//!
//! `Variant` types are described by [`VariantType`](../struct.VariantType.html)
//! "type strings".
//!
//! Although `GVariant` supports arbitrarily complex types, this binding is
//! currently limited to the basic ones: `bool`, `u8`, `i16`, `u16`, `i32`,
//! `u32`, `i64`, `u64`, `f64` and `&str`/`String`.
//!
//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::Variant;
//!
//! // Using the `ToVariant` trait.
//! let num = 10.to_variant();
//!
//! // `is` tests the type of the value.
//! assert!(num.is::<i32>());
//!
//! // `get` tries to extract the value.
//! assert_eq!(num.get::<i32>(), Some(10));
//! assert_eq!(num.get::<u32>(), None);
//!
//! // `Variant` implements `From`
//! let hello = Variant::from("Hello!");
//!
//! // `get_str` tries to borrow a string slice.
//! assert_eq!(hello.get_str(), Some("Hello!"));
//! assert_eq!(num.get_str(), None);
//! ```

use VariantTy;
use ffi as glib_ffi;
use gobject_ffi;
use translate::*;
use std::borrow::Cow;
use std::cmp::{PartialEq, Eq};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::slice;
use std::str;
use std::ptr;
use std::mem;

glib_wrapper! {
    /// A generic immutable value capable of carrying various types.
    ///
    /// See the [module documentation](index.html) for more details.
    pub struct Variant(Shared<glib_ffi::GVariant>);

    match fn {
        ref => |ptr| glib_ffi::g_variant_ref_sink(ptr),
        unref => |ptr| glib_ffi::g_variant_unref(ptr),
        get_type => || glib_ffi::g_variant_type_get_gtype(),
    }
}

impl Variant {
    /// Returns the type of the value.
    pub fn type_(&self) -> &VariantTy {
        unsafe { VariantTy::from_ptr(glib_ffi::g_variant_get_type(self.to_glib_none().0)) }
    }

    /// Returns `true` if the type of the value corresponds to `T`.
    #[inline]
    pub fn is<T: StaticVariantType>(&self) -> bool {
        self.type_() == T::static_variant_type()
    }

    /// Tries to extract a value of type `T`.
    ///
    /// Returns `Some` if `T` matches the variant's type.
    #[inline]
    pub fn get<T: FromVariant>(&self) -> Option<T> {
        T::from_variant(self)
    }

    /// Tries to extract a `&str`.
    ///
    /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
    /// strings).
    pub fn get_str(&self) -> Option<&str> {
        unsafe {
            match self.type_().to_str() {
                "s" | "o" | "g" => {
                    let mut len = 0;
                    let ptr = glib_ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
                    let ret = str::from_utf8_unchecked(
                        slice::from_raw_parts(ptr as *const u8, len as usize));
                    Some(ret)
                }
                _ => None,
            }
        }
    }
}

unsafe impl Send for Variant { }
unsafe impl Sync for Variant { }

impl fmt::Debug for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Variant {{ ptr: {:?}, type: \"{}\", value: {} }}",
            self.to_glib_none().0, self.type_(), self))
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let serialized: String = unsafe {
            from_glib_full(glib_ffi::g_variant_print(self.to_glib_none().0, false.to_glib()))
        };
        f.write_str(&serialized)
    }
}

impl PartialEq for Variant {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_variant_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Variant { }

impl Hash for Variant {
    fn hash<H: Hasher>(&self, state: &mut H) {
        unsafe {
            state.write_u32(glib_ffi::g_variant_hash(self.to_glib_none().0 as *const _))
        }
    }
}

/// Converts to `Variant`.
pub trait ToVariant {
    /// Returns a `Variant` clone of `self`.
    fn to_variant(&self) -> Variant;
}

/// Extracts a value.
pub trait FromVariant: Sized + StaticVariantType {
    /// Tries to extract a value.
    ///
    /// Returns `Some` if the variant's type matches `Self`.
    fn from_variant(variant: &Variant) -> Option<Self>;
}

/// Returns `VariantType` of `Self`.
pub trait StaticVariantType {
    /// Returns the `VariantType` corresponding to `Self`.
    fn static_variant_type() -> Cow<'static, VariantTy>;
}

impl<'a, T: ?Sized + ToVariant> ToVariant for &'a T {
    fn to_variant(&self) -> Variant {
        <T as ToVariant>::to_variant(self)
    }
}

impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        <T as StaticVariantType>::static_variant_type()
    }
}

macro_rules! impl_numeric {
    ($name:ty, $type_str:expr, $new_fn:ident, $get_fn:ident) => {
        impl StaticVariantType for $name {
            fn static_variant_type() -> Cow<'static, VariantTy> {
                unsafe { VariantTy::from_str_unchecked($type_str).into() }
            }
        }

        impl ToVariant for $name {
            fn to_variant(&self) -> Variant {
                unsafe { from_glib_none(glib_ffi::$new_fn(*self)) }
            }
        }

        impl FromVariant for $name {
            fn from_variant(variant: &Variant) -> Option<Self> {
                unsafe {
                    if variant.is::<Self>() {
                        Some(glib_ffi::$get_fn(variant.to_glib_none().0))
                    } else {
                        None
                    }
                }
            }
        }
    }
}

impl_numeric!(u8, "y", g_variant_new_byte, g_variant_get_byte);
impl_numeric!(i16, "n", g_variant_new_int16, g_variant_get_int16);
impl_numeric!(u16, "q", g_variant_new_uint16, g_variant_get_uint16);
impl_numeric!(i32, "i", g_variant_new_int32, g_variant_get_int32);
impl_numeric!(u32, "u", g_variant_new_uint32, g_variant_get_uint32);
impl_numeric!(i64, "x", g_variant_new_int64, g_variant_get_int64);
impl_numeric!(u64, "t", g_variant_new_uint64, g_variant_get_uint64);
impl_numeric!(f64, "d", g_variant_new_double, g_variant_get_double);

impl StaticVariantType for bool {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("b").into() }
    }
}

impl ToVariant for bool {
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_boolean(self.to_glib())) }
    }
}

impl FromVariant for bool {
    fn from_variant(variant: &Variant) -> Option<Self> {
        unsafe {
            if variant.is::<Self>() {
                Some(from_glib(glib_ffi::g_variant_get_boolean(variant.to_glib_none().0)))
            } else {
                None
            }
        }
    }
}

impl StaticVariantType for String {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for String {
    fn to_variant(&self) -> Variant {
        self[..].to_variant()
    }
}

impl FromVariant for String {
    fn from_variant(variant: &Variant) -> Option<Self> {
        variant.get_str().map(String::from)
    }
}

impl StaticVariantType for str {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for str {
    #[cfg(any(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_take_string(self.to_glib_full())) }
    }

    #[cfg(not(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_string(self.to_glib_none().0)) }
    }
}

impl<T: ToVariant> From<T> for Variant {
    fn from(value: T) -> Variant {
        value.to_variant()
    }
}

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

    macro_rules! unsigned {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    n /= 2;
                }
            }
        }
    }

    macro_rules! signed {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    let v = Variant::from(-n);
                    assert_eq!(v.get(), Some(-n));
                    n /= 2;
                }
            }
        }
    }

    unsigned!(test_u8, u8);
    unsigned!(test_u16, u16);
    unsigned!(test_u32, u32);
    unsigned!(test_u64, u64);
    signed!(test_i16, i16);
    signed!(test_i32, i32);
    signed!(test_i64, i64);

    #[test]
    fn test_str() {
        let s = "this is a test";
        let v = Variant::from(s);
        assert_eq!(v.get_str(), Some(s));
    }

    #[test]
    fn test_string() {
        let s = String::from("this is a test");
        let v = Variant::from(s.clone());
        assert_eq!(v.get(), Some(s.clone()));
    }

    #[test]
    fn test_eq() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        assert_eq!(v1, v2);
        assert!(v1 != v3);
    }

    #[test]
    fn test_hash() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        let mut set = HashSet::new();
        set.insert(v1);
        assert!(set.contains(&v2));
        assert!(!set.contains(&v3));
    }
}
<commit_msg>Implement PartialOrd for Variant<commit_after>// Copyright 2013-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `Variant` binding and helper traits.
//!
//! [`Variant`](struct.Variant.html) is an immutable dynamically-typed generic
//! container. Its type and value are defined at construction and never change.
//!
//! `Variant` types are described by [`VariantType`](../struct.VariantType.html)
//! "type strings".
//!
//! Although `GVariant` supports arbitrarily complex types, this binding is
//! currently limited to the basic ones: `bool`, `u8`, `i16`, `u16`, `i32`,
//! `u32`, `i64`, `u64`, `f64` and `&str`/`String`.
//!
//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::Variant;
//!
//! // Using the `ToVariant` trait.
//! let num = 10.to_variant();
//!
//! // `is` tests the type of the value.
//! assert!(num.is::<i32>());
//!
//! // `get` tries to extract the value.
//! assert_eq!(num.get::<i32>(), Some(10));
//! assert_eq!(num.get::<u32>(), None);
//!
//! // `Variant` implements `From`
//! let hello = Variant::from("Hello!");
//!
//! // `get_str` tries to borrow a string slice.
//! assert_eq!(hello.get_str(), Some("Hello!"));
//! assert_eq!(num.get_str(), None);
//! ```

use VariantTy;
use ffi as glib_ffi;
use gobject_ffi;
use translate::*;
use std::borrow::Cow;
use std::cmp::{PartialEq, Eq, PartialOrd, Ordering};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::slice;
use std::str;
use std::ptr;
use std::mem;

glib_wrapper! {
    /// A generic immutable value capable of carrying various types.
    ///
    /// See the [module documentation](index.html) for more details.
    pub struct Variant(Shared<glib_ffi::GVariant>);

    match fn {
        ref => |ptr| glib_ffi::g_variant_ref_sink(ptr),
        unref => |ptr| glib_ffi::g_variant_unref(ptr),
        get_type => || glib_ffi::g_variant_type_get_gtype(),
    }
}

impl Variant {
    /// Returns the type of the value.
    pub fn type_(&self) -> &VariantTy {
        unsafe { VariantTy::from_ptr(glib_ffi::g_variant_get_type(self.to_glib_none().0)) }
    }

    /// Returns `true` if the type of the value corresponds to `T`.
    #[inline]
    pub fn is<T: StaticVariantType>(&self) -> bool {
        self.type_() == T::static_variant_type()
    }

    /// Tries to extract a value of type `T`.
    ///
    /// Returns `Some` if `T` matches the variant's type.
    #[inline]
    pub fn get<T: FromVariant>(&self) -> Option<T> {
        T::from_variant(self)
    }

    /// Tries to extract a `&str`.
    ///
    /// Returns `Some` if the variant has a string type (`s`, `o` or `g` type
    /// strings).
    pub fn get_str(&self) -> Option<&str> {
        unsafe {
            match self.type_().to_str() {
                "s" | "o" | "g" => {
                    let mut len = 0;
                    let ptr = glib_ffi::g_variant_get_string(self.to_glib_none().0, &mut len);
                    let ret = str::from_utf8_unchecked(
                        slice::from_raw_parts(ptr as *const u8, len as usize));
                    Some(ret)
                }
                _ => None,
            }
        }
    }
}

unsafe impl Send for Variant { }
unsafe impl Sync for Variant { }

impl fmt::Debug for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Variant {{ ptr: {:?}, type: \"{}\", value: {} }}",
            self.to_glib_none().0, self.type_(), self))
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let serialized: String = unsafe {
            from_glib_full(glib_ffi::g_variant_print(self.to_glib_none().0, false.to_glib()))
        };
        f.write_str(&serialized)
    }
}

impl PartialEq for Variant {
    fn eq(&self, other: &Self) -> bool {
        unsafe {
            from_glib(
                glib_ffi::g_variant_equal(self.to_glib_none().0 as *const _,
                    other.to_glib_none().0 as *const _))
        }
    }
}

impl Eq for Variant { }

impl PartialOrd for Variant {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        unsafe {
            if glib_ffi::g_variant_classify(self.to_glib_none().0) !=
               glib_ffi::g_variant_classify(other.to_glib_none().0) {
                return None;
            }

            if glib_ffi::g_variant_is_container(self.to_glib_none().0) != glib_ffi::GFALSE {
                return None;
            }

            let res = glib_ffi::g_variant_compare(self.to_glib_none().0 as *const _, other.to_glib_none().0 as *const _);
            if res < 0 {
                Some(Ordering::Less)
            } else if res > 0 {
                Some(Ordering::Equal)
            } else {
                Some(Ordering::Greater)
            }
        }
    }
}

impl Hash for Variant {
    fn hash<H: Hasher>(&self, state: &mut H) {
        unsafe {
            state.write_u32(glib_ffi::g_variant_hash(self.to_glib_none().0 as *const _))
        }
    }
}

/// Converts to `Variant`.
pub trait ToVariant {
    /// Returns a `Variant` clone of `self`.
    fn to_variant(&self) -> Variant;
}

/// Extracts a value.
pub trait FromVariant: Sized + StaticVariantType {
    /// Tries to extract a value.
    ///
    /// Returns `Some` if the variant's type matches `Self`.
    fn from_variant(variant: &Variant) -> Option<Self>;
}

/// Returns `VariantType` of `Self`.
pub trait StaticVariantType {
    /// Returns the `VariantType` corresponding to `Self`.
    fn static_variant_type() -> Cow<'static, VariantTy>;
}

impl<'a, T: ?Sized + ToVariant> ToVariant for &'a T {
    fn to_variant(&self) -> Variant {
        <T as ToVariant>::to_variant(self)
    }
}

impl<'a, T: ?Sized + StaticVariantType> StaticVariantType for &'a T {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        <T as StaticVariantType>::static_variant_type()
    }
}

macro_rules! impl_numeric {
    ($name:ty, $type_str:expr, $new_fn:ident, $get_fn:ident) => {
        impl StaticVariantType for $name {
            fn static_variant_type() -> Cow<'static, VariantTy> {
                unsafe { VariantTy::from_str_unchecked($type_str).into() }
            }
        }

        impl ToVariant for $name {
            fn to_variant(&self) -> Variant {
                unsafe { from_glib_none(glib_ffi::$new_fn(*self)) }
            }
        }

        impl FromVariant for $name {
            fn from_variant(variant: &Variant) -> Option<Self> {
                unsafe {
                    if variant.is::<Self>() {
                        Some(glib_ffi::$get_fn(variant.to_glib_none().0))
                    } else {
                        None
                    }
                }
            }
        }
    }
}

impl_numeric!(u8, "y", g_variant_new_byte, g_variant_get_byte);
impl_numeric!(i16, "n", g_variant_new_int16, g_variant_get_int16);
impl_numeric!(u16, "q", g_variant_new_uint16, g_variant_get_uint16);
impl_numeric!(i32, "i", g_variant_new_int32, g_variant_get_int32);
impl_numeric!(u32, "u", g_variant_new_uint32, g_variant_get_uint32);
impl_numeric!(i64, "x", g_variant_new_int64, g_variant_get_int64);
impl_numeric!(u64, "t", g_variant_new_uint64, g_variant_get_uint64);
impl_numeric!(f64, "d", g_variant_new_double, g_variant_get_double);

impl StaticVariantType for bool {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("b").into() }
    }
}

impl ToVariant for bool {
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_boolean(self.to_glib())) }
    }
}

impl FromVariant for bool {
    fn from_variant(variant: &Variant) -> Option<Self> {
        unsafe {
            if variant.is::<Self>() {
                Some(from_glib(glib_ffi::g_variant_get_boolean(variant.to_glib_none().0)))
            } else {
                None
            }
        }
    }
}

impl StaticVariantType for String {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for String {
    fn to_variant(&self) -> Variant {
        self[..].to_variant()
    }
}

impl FromVariant for String {
    fn from_variant(variant: &Variant) -> Option<Self> {
        variant.get_str().map(String::from)
    }
}

impl StaticVariantType for str {
    fn static_variant_type() -> Cow<'static, VariantTy> {
        unsafe { VariantTy::from_str_unchecked("s").into() }
    }
}

impl ToVariant for str {
    #[cfg(any(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_take_string(self.to_glib_full())) }
    }

    #[cfg(not(feature = "v2_38"))]
    fn to_variant(&self) -> Variant {
        unsafe { from_glib_none(glib_ffi::g_variant_new_string(self.to_glib_none().0)) }
    }
}

impl<T: ToVariant> From<T> for Variant {
    fn from(value: T) -> Variant {
        value.to_variant()
    }
}

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

    macro_rules! unsigned {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    n /= 2;
                }
            }
        }
    }

    macro_rules! signed {
        ($name:ident, $ty:ident) => {
            #[test]
            fn $name() {
                let mut n = $ty::max_value();
                while n > 0  {
                    let v = Variant::from(n);
                    assert_eq!(v.get(), Some(n));
                    let v = Variant::from(-n);
                    assert_eq!(v.get(), Some(-n));
                    n /= 2;
                }
            }
        }
    }

    unsigned!(test_u8, u8);
    unsigned!(test_u16, u16);
    unsigned!(test_u32, u32);
    unsigned!(test_u64, u64);
    signed!(test_i16, i16);
    signed!(test_i32, i32);
    signed!(test_i64, i64);

    #[test]
    fn test_str() {
        let s = "this is a test";
        let v = Variant::from(s);
        assert_eq!(v.get_str(), Some(s));
    }

    #[test]
    fn test_string() {
        let s = String::from("this is a test");
        let v = Variant::from(s.clone());
        assert_eq!(v.get(), Some(s.clone()));
    }

    #[test]
    fn test_eq() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        assert_eq!(v1, v2);
        assert!(v1 != v3);
    }

    #[test]
    fn test_hash() {
        let v1 = Variant::from("this is a test");
        let v2 = Variant::from("this is a test");
        let v3 = Variant::from("test");
        let mut set = HashSet::new();
        set.insert(v1);
        assert!(set.contains(&v2));
        assert!(!set.contains(&v3));
    }
}
<|endoftext|>


<commit_before>use utils::bigint::{M256, U256, U512};
use utils::gas::Gas;
use utils::address::Address;
use vm::{Machine, Memory, Stack, PC, Error, Result};
use vm::opcode::Opcode;
use vm::machine::MachineState;
use transaction::Transaction;
use blockchain::Block;
use std::cmp::{min, max};

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_EXTCODE: usize = 700;
const G_BALANCE: usize = 400;
const G_SLOAD: usize = 200;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_SUICIDE: usize = 5000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSITE: usize = 200;
const G_CALL: usize = 700;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_EXPBYTE: usize = 10;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn memory_cost(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

fn sstore_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let index = machine.stack().peek(0)?;
    let value = machine.stack().peek(1)?;
    let address = machine.transaction().callee();

    if value != M256::zero() && machine.block().account_storage(address, index) == M256::zero() {
        Ok(G_SSET.into())
    } else {
        Ok(G_SRESET.into())
    }
}

fn call_cost<M: MachineState>(machine: &M, available_gas: Gas) -> Result<Gas> {
    Ok(gascap_cost(machine, available_gas)? + extra_cost(machine)?)
}

fn callgas_cost<M: MachineState>(machine: &M, available_gas: Gas) -> Result<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(gascap_cost(machine, available_gas)? + G_CALLSTIPEND.into())
    } else {
        Ok(gascap_cost(machine, available_gas)?)
    }
}

fn gascap_cost<M: MachineState>(machine: &M, available_gas: Gas) -> Result<Gas> {
    let base2 = machine.stack().peek(0)?.into();

    if available_gas >= extra_cost(machine)? {
        let base1 = available_gas - extra_cost(machine)?;
        Ok(min(base1 - base1 / Gas::from(64u64), base2))
    } else {
        Ok(base2)
    }
}

fn extra_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    Ok(Gas::from(G_CALL) + xfer_cost(machine)? + new_cost(machine)?)
}

fn xfer_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(G_CALLVALUE.into())
    } else {
        Ok(Gas::zero())
    }
}

fn new_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    if address == Address::default() {
        Ok(G_NEWACCOUNT.into())
    } else {
        Ok(Gas::zero())
    }
}

fn suicide_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    Ok(Gas::from(G_SUICIDE) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    })
}

#[derive(Clone, Copy, Debug)]
pub struct CostAggregrator(Gas);

impl CostAggregrator {
    pub fn active_memory_len(&self) -> M256 {
        self.0.into()
    }
}

impl Default for CostAggregrator {
    fn default() -> CostAggregrator {
        CostAggregrator(Gas::zero())
    }
}

fn memory_gas_cost<M: MachineState>(opcode: Opcode, machine: &M, aggregrator: CostAggregrator)
                               -> Result<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let current = aggregrator.0;
    let next = match opcode {
        Opcode::SHA3 | Opcode::CODECOPY | Opcode::RETURN => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(1)?.into();
            max(Gas::from(from) + Gas::from(len), current)
        },
        Opcode::MLOAD | Opcode::MSTORE => {
            let from: U256 = stack.peek(0)?.into();
            max(Gas::from(from) + Gas::from(32u64), current)
        },
        Opcode::MSTORE8 => {
            let from: U256 = stack.peek(0)?.into();
            max(Gas::from(from) + Gas::from(1u64), current)
        },
        Opcode::CREATE => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(2)?.into();
            max(Gas::from(from) + Gas::from(len), current)
        },
        _ => {
            current
        }
    };
    Ok((memory_cost(next) - memory_cost(current), CostAggregrator(next)))
}

pub fn gas_cost<M: MachineState>(opcode: Opcode, machine: &M, available_gas: Gas, aggregrator: CostAggregrator)
                            -> Result<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let self_cost: Gas = match opcode {
        Opcode::CALL | Opcode::CALLCODE |
        Opcode::DELEGATECALL => call_cost(machine, available_gas)?,
        Opcode::SUICIDE => suicide_cost(machine)?,
        Opcode::SSTORE => sstore_cost(machine)?,

        Opcode::SHA3 => {
            let len = stack.peek(1)?;
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * (Gas::from(len) / Gas::from(32u64))).into()
        },

        Opcode::LOG(v) => {
            let len = stack.peek(1)?;
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Opcode::EXTCODECOPY => {
            let len = stack.peek(2)?;
            (Gas::from(G_EXTCODE) + Gas::from(G_COPY) * (Gas::from(len) / Gas::from(32u64))).into()
        },

        Opcode::CALLDATACOPY | Opcode::CODECOPY => {
            let len = stack.peek(2)?;
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * (Gas::from(len) / Gas::from(32u64))).into()
        },

        Opcode::EXP => {
            if stack.peek(1)? == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(G_EXPBYTE) * (Gas::from(1u64) + Gas::from(stack.peek(1)?.log2floor()) / Gas::from(8u64))
            }
        }

        Opcode::CREATE => G_CREATE.into(),
        Opcode::JUMPDEST => G_JUMPDEST.into(),
        Opcode::SLOAD => G_SLOAD.into(),

        // W_zero
        Opcode::STOP | Opcode::RETURN
            => G_ZERO.into(),

        // W_base
        Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
        Opcode::CALLVALUE | Opcode::CALLDATASIZE |
        Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
        Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
        Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
        Opcode::MSIZE | Opcode::GAS
            => G_BASE.into(),

        // W_verylow
        Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
        Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
        Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
        Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
        Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
        Opcode::DUP(_) | Opcode::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
        Opcode::SMOD | Opcode::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
            => G_MID.into(),

        // W_high
        Opcode::JUMPI => G_HIGH.into(),

        // W_extcode
        Opcode::EXTCODESIZE => G_EXTCODE.into(),

        Opcode::BALANCE => G_BALANCE.into(),
        Opcode::BLOCKHASH => G_BLOCKHASH.into(),
        Opcode::INVALID => Gas::zero(),
    };
    let (memory_gas, agg) = memory_gas_cost(opcode, machine, aggregrator)?;
    Ok((self_cost + memory_gas, agg))
}
<commit_msg>Problem: memory gas cost was incorrect Solution: fix it<commit_after>use utils::bigint::{M256, U256, U512};
use utils::gas::Gas;
use utils::address::Address;
use vm::{Machine, Memory, Stack, PC, Error, Result};
use vm::opcode::Opcode;
use vm::machine::MachineState;
use transaction::Transaction;
use blockchain::Block;
use std::cmp::{min, max};

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_EXTCODE: usize = 700;
const G_BALANCE: usize = 400;
const G_SLOAD: usize = 200;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_SUICIDE: usize = 5000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSITE: usize = 200;
const G_CALL: usize = 700;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_EXPBYTE: usize = 10;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn memory_cost(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

fn sstore_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let index = machine.stack().peek(0)?;
    let value = machine.stack().peek(1)?;
    let address = machine.transaction().callee();

    if value != M256::zero() && machine.block().account_storage(address, index) == M256::zero() {
        Ok(G_SSET.into())
    } else {
        Ok(G_SRESET.into())
    }
}

fn call_cost<M: MachineState>(machine: &M, available_gas: Gas) -> Result<Gas> {
    Ok(gascap_cost(machine, available_gas)? + extra_cost(machine)?)
}

fn callgas_cost<M: MachineState>(machine: &M, available_gas: Gas) -> Result<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(gascap_cost(machine, available_gas)? + G_CALLSTIPEND.into())
    } else {
        Ok(gascap_cost(machine, available_gas)?)
    }
}

fn gascap_cost<M: MachineState>(machine: &M, available_gas: Gas) -> Result<Gas> {
    let base2 = machine.stack().peek(0)?.into();

    if available_gas >= extra_cost(machine)? {
        let base1 = available_gas - extra_cost(machine)?;
        Ok(min(base1 - base1 / Gas::from(64u64), base2))
    } else {
        Ok(base2)
    }
}

fn extra_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    Ok(Gas::from(G_CALL) + xfer_cost(machine)? + new_cost(machine)?)
}

fn xfer_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(G_CALLVALUE.into())
    } else {
        Ok(Gas::zero())
    }
}

fn new_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    if address == Address::default() {
        Ok(G_NEWACCOUNT.into())
    } else {
        Ok(Gas::zero())
    }
}

fn suicide_cost<M: MachineState>(machine: &M) -> Result<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    Ok(Gas::from(G_SUICIDE) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    })
}

#[derive(Clone, Copy, Debug)]
pub struct CostAggregrator(Gas);

impl CostAggregrator {
    pub fn active_memory_len(&self) -> M256 {
        self.0.into()
    }
}

impl Default for CostAggregrator {
    fn default() -> CostAggregrator {
        CostAggregrator(Gas::zero())
    }
}

fn memory_gas_cost<M: MachineState>(opcode: Opcode, machine: &M, aggregrator: CostAggregrator)
                               -> Result<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let current = aggregrator.0;
    let next = match opcode {
        Opcode::SHA3 | Opcode::CODECOPY | Opcode::RETURN => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(1)?.into();
            if len == U256::zero() {
                current
            } else {
                max((Gas::from(from) + Gas::from(len)) / Gas::from(32u64), current)
            }
        },
        Opcode::MLOAD | Opcode::MSTORE => {
            let from: U256 = stack.peek(0)?.into();
            max((Gas::from(from) + Gas::from(32u64)) / Gas::from(32u64), current)
        },
        Opcode::MSTORE8 => {
            let from: U256 = stack.peek(0)?.into();
            max((Gas::from(from) + Gas::from(1u64)) / Gas::from(32u64), current)
        },
        Opcode::CREATE => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(2)?.into();
            if len == U256::zero() {
                current
            } else {
                max((Gas::from(from) + Gas::from(len)) / Gas::from(32u64), current)
            }
        },
        _ => {
            current
        }
    };
    Ok((memory_cost(next) - memory_cost(current), CostAggregrator(next)))
}

pub fn gas_cost<M: MachineState>(opcode: Opcode, machine: &M, available_gas: Gas, aggregrator: CostAggregrator)
                            -> Result<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let self_cost: Gas = match opcode {
        Opcode::CALL | Opcode::CALLCODE |
        Opcode::DELEGATECALL => call_cost(machine, available_gas)?,
        Opcode::SUICIDE => suicide_cost(machine)?,
        Opcode::SSTORE => sstore_cost(machine)?,

        Opcode::SHA3 => {
            let len = stack.peek(1)?;
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * (Gas::from(len) / Gas::from(32u64))).into()
        },

        Opcode::LOG(v) => {
            let len = stack.peek(1)?;
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Opcode::EXTCODECOPY => {
            let len = stack.peek(2)?;
            (Gas::from(G_EXTCODE) + Gas::from(G_COPY) * (Gas::from(len) / Gas::from(32u64))).into()
        },

        Opcode::CALLDATACOPY | Opcode::CODECOPY => {
            let len = stack.peek(2)?;
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * (Gas::from(len) / Gas::from(32u64))).into()
        },

        Opcode::EXP => {
            if stack.peek(1)? == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(G_EXPBYTE) * (Gas::from(1u64) + Gas::from(stack.peek(1)?.log2floor()) / Gas::from(8u64))
            }
        }

        Opcode::CREATE => G_CREATE.into(),
        Opcode::JUMPDEST => G_JUMPDEST.into(),
        Opcode::SLOAD => G_SLOAD.into(),

        // W_zero
        Opcode::STOP | Opcode::RETURN
            => G_ZERO.into(),

        // W_base
        Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
        Opcode::CALLVALUE | Opcode::CALLDATASIZE |
        Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
        Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
        Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
        Opcode::MSIZE | Opcode::GAS
            => G_BASE.into(),

        // W_verylow
        Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
        Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
        Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
        Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
        Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
        Opcode::DUP(_) | Opcode::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
        Opcode::SMOD | Opcode::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
            => G_MID.into(),

        // W_high
        Opcode::JUMPI => G_HIGH.into(),

        // W_extcode
        Opcode::EXTCODESIZE => G_EXTCODE.into(),

        Opcode::BALANCE => G_BALANCE.into(),
        Opcode::BLOCKHASH => G_BLOCKHASH.into(),
        Opcode::INVALID => Gas::zero(),
    };
    let (memory_gas, agg) = memory_gas_cost(opcode, machine, aggregrator)?;
    Ok((self_cost + memory_gas, agg))
}
<|endoftext|>


<commit_before>use std::net::{TcpStream, Shutdown};
use std::io::{Stdin, stdin, stdout, Read, Write, Error, Result, Cursor};
use std::fs::File;
use std::env;
use std::str;
use std::option::Option;
use std::process::{Command, Child, exit};
use std::path::PathBuf;
use std::thread::sleep;
use std::time::Duration;
use wait_timeout::ChildExt;
use Input::*;

extern crate wait_timeout;

const MAX_RETRIES: usize = 5;

const JGRAB_INFO: &str = "\
=============== JGrab Client ================
 - https://github.com/renatoathaydes/jgrab -
=============================================
Jgrab can execute Java code from stdin (if not given any argument),
a Java file, or a Java snippet.

This is the native JGrab Client, written in Rust!

A Java daemon is started the first time the JGrab Client is run so
that subsequent runs are much faster.";

const JGRAB_USAGE: &str = "\
Usage:
  jgrab [<option> | java_file | -e java_snippet]
Options:
  --stop -s
    Stops the JGrab daemon.
  --help -h
    Shows this usage help.";

/// All possible sources of input for the JGrab Client
enum Input {
    FileInput(File),
    StdinInput(Stdin),
    TextInput(Cursor<String>)
}

impl Read for Input {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match *self {
            FileInput(ref mut r) => r.read(buf),
            StdinInput(ref mut r) => r.read(buf),
            TextInput(ref mut r) => r.read(buf),
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let input: Input;

    if args.len() == 1 {
        // no args, pipe stdin
        input = StdinInput(stdin());
    } else if args.len() == 2 && !args[1].starts_with('-') {
        // there's one argument and it is not an option, so it must be a file

        match File::open(&args[1]) {
            Ok(file) => input = FileInput(file),
            Err(err) => error(&format!("unable to read file: {}", err))
        }
    } else if args.len() == 2 {
        match args[1].trim() {
            "--help" | "-h" => {
                println!("{}\n\n{}", JGRAB_INFO, JGRAB_USAGE);
                return
            }
            "--stop" | "-s" => {
                input = TextInput(Cursor::new("--stop".to_string()))
            }
            _ => {
                usage_error(&format!("invalid option"));
            }
        }
    } else {
        // just pass on the arguments to JGrab
        input = TextInput(Cursor::new(create_message(&args)))
    }

    send_message_retrying(input);
}

fn create_message(args: &Vec<String>) -> String {
    args[1..].join(" ")
}

fn send_message_retrying<R: Read>(mut reader: R) {
    if let Some(_) = send_message(&mut reader, false) {
        // failed to connect, try to start the daemon, then retry
        let mut retries = MAX_RETRIES;

        let mut child = start_daemon();
        check_status(&mut child);

        while retries > 0 {
            if let Some(err) = send_message(&mut reader, true) {
                check_status(&mut child);

                log(&format!("unable to connect to JGrab daemon: {}", err));
                log(&format!("will re-try {} more times", &mut retries));
                retries -= 1;
            } else {
                break // success
            }
        }

        if retries == 0 {
            error("unable to start JGrab daemon. \
                   Make sure JGrab's port [5002] is not already bound");
        }
    }
}

fn send_message<R: Read>(reader: &mut R,
                         is_retry: bool) -> Option<Error> {
    match TcpStream::connect("127.0.0.1:5002") {
        Ok(mut stream) => {
            if is_retry {
                log("Connected!");
            }

            let mut socket_message = [0u8; 1024];

            loop {
                match reader.read(&mut socket_message) {
                    Ok(n) => {
                        if n == 0 {
                            break;
                        } else {
                            stream.write(&socket_message[0..n]).unwrap();
                        }
                    }
                    Err(err) => error(&err.to_string())
                }
            }

            stream.shutdown(Shutdown::Write).unwrap();

            let mut client_buffer = socket_message;

            loop {
                match stream.read(&mut client_buffer) {
                    Ok(n) => {
                        if n == 0 {
                            break;
                        } else {
                            stdout().write(&client_buffer[0..n]).unwrap();
                        }
                    }
                    Err(err) => error(&err.to_string())
                }
            }

            Option::None
        }
        Err(err) => Option::Some(err)
    }
}

fn start_daemon() -> Child {
    log("Starting daemon");

    if let Some(user_home) = env::home_dir() {
        let mut jgrab_jar: PathBuf = user_home;
        jgrab_jar.push(".jgrab");
        jgrab_jar.push("jgrab.jar");

        if jgrab_jar.as_path().is_file() {
            let cmd = Command::new("java")
                .arg("-jar")
                .arg(jgrab_jar.into_os_string().into_string().unwrap())
                .arg("--daemon")
                .spawn();

            match cmd {
                Ok(child) => {
                    log(&format!("Daemon started, pid={}", child.id()));
                    child
                }
                Err(err) => error(&err.to_string())
            }
        } else {
            error("The JGrab jar is not installed! Please install it as explained \
                   in https://github.com/renatoathaydes/jgrab");
        }
    } else {
        error("user.home could not be found, making it impossible to start the JGrab Daemon");
    }
}

fn check_status(child: &mut Child) {
    let timeout = Duration::from_secs(1);

    match child.wait_timeout(timeout) {
        Ok(Some(status)) => error(&format!(
            "The JGrab daemon has died prematurely, exit code was {}", status)),
        Ok(None) => {
            // give time for the socket server to become active
            sleep(Duration::from_secs(1));
        }
        Err(e) => error(&format!(
            "unable to wait for JGrab daemon process status: {}", e)),
    }
}

fn log(message: &str) {
    println!("=== JGrab Client === {}", message)
}

fn usage_error(message: &str) -> ! {
    println!("### {} ###\n\n{}", message, JGRAB_USAGE);
    exit(2)
}

fn error(message: &str) -> ! {
    println!("### JGrab Client Error - {} ###", message);
    exit(1)
}
<commit_msg>Don't start daemon if --stop is called and daemon is not running.<commit_after>use std::net::{TcpStream, Shutdown};
use std::io::{Stdin, stdin, stdout, Read, Write, Error, Result, Cursor};
use std::fs::File;
use std::env;
use std::str;
use std::option::Option;
use std::process::{Command, Child, exit};
use std::path::PathBuf;
use std::thread::sleep;
use std::time::Duration;
use wait_timeout::ChildExt;
use Input::*;

extern crate wait_timeout;

const MAX_RETRIES: usize = 5;

const JGRAB_INFO: &str = "\
=============== JGrab Client ================
 - https://github.com/renatoathaydes/jgrab -
=============================================
Jgrab can execute Java code from stdin (if not given any argument),
a Java file, or a Java snippet.

This is the native JGrab Client, written in Rust!

A Java daemon is started the first time the JGrab Client is run so
that subsequent runs are much faster.";

const JGRAB_USAGE: &str = "\
Usage:
  jgrab [<option> | java_file | -e java_snippet]
Options:
  --stop -s
    Stops the JGrab daemon.
  --help -h
    Shows usage help.";

/// All possible sources of input for the JGrab Client
enum Input {
    FileInput(File),
    StdinInput(Stdin),
    TextInput(Cursor<String>)
}

impl Read for Input {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        match *self {
            FileInput(ref mut r) => r.read(buf),
            StdinInput(ref mut r) => r.read(buf),
            TextInput(ref mut r) => r.read(buf),
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();

    let input: Input;

    if args.len() == 1 {
        // no args, pipe stdin
        input = StdinInput(stdin());
    } else if args.len() == 2 && !args[1].starts_with('-') {
        // there's one argument and it is not an option, so it must be a file

        match File::open(&args[1]) {
            Ok(file) => input = FileInput(file),
            Err(err) => error(&format!("unable to read file: {}", err))
        }
    } else if args.len() == 2 {
        match args[1].trim() {
            "--help" | "-h" => {
                println!("{}\n\n{}", JGRAB_INFO, JGRAB_USAGE);
                return
            }
            "--stop" | "-s" => {
                if let Err(_) = connect() {
                    log("daemon is not running");
                    return
                }
                input = TextInput(Cursor::new("--stop".to_string()))
            }
            _ => {
                usage_error(&format!("invalid option"));
            }
        }
    } else {
        // just pass on the arguments to JGrab
        input = TextInput(Cursor::new(create_message(&args)))
    }

    send_message_retrying(input);
}

fn create_message(args: &Vec<String>) -> String {
    args[1..].join(" ")
}

fn send_message_retrying<R: Read>(mut reader: R) {
    if let Some(_) = send_message(&mut reader, false) {
        // failed to connect, try to start the daemon, then retry
        let mut retries = MAX_RETRIES;

        let mut child = start_daemon();
        check_status(&mut child);

        while retries > 0 {
            if let Some(err) = send_message(&mut reader, true) {
                check_status(&mut child);

                log(&format!("unable to connect to JGrab daemon: {}", err));
                log(&format!("will re-try {} more times", &mut retries));
                retries -= 1;
            } else {
                break // success
            }
        }

        if retries == 0 {
            error("unable to start JGrab daemon. \
                   Make sure JGrab's port [5002] is not already bound");
        }
    }
}

fn connect() -> Result<TcpStream> {
    TcpStream::connect("127.0.0.1:5002")
}

fn send_message<R: Read>(reader: &mut R,
                         is_retry: bool) -> Option<Error> {
    match connect() {
        Ok(mut stream) => {
            if is_retry {
                log("Connected!");
            }

            let mut socket_message = [0u8; 1024];

            loop {
                match reader.read(&mut socket_message) {
                    Ok(n) => {
                        if n == 0 {
                            break;
                        } else {
                            stream.write(&socket_message[0..n]).unwrap();
                        }
                    }
                    Err(err) => error(&err.to_string())
                }
            }

            stream.shutdown(Shutdown::Write).unwrap();

            let mut client_buffer = socket_message;

            loop {
                match stream.read(&mut client_buffer) {
                    Ok(n) => {
                        if n == 0 {
                            break;
                        } else {
                            stdout().write(&client_buffer[0..n]).unwrap();
                        }
                    }
                    Err(err) => error(&err.to_string())
                }
            }

            Option::None
        }
        Err(err) => Option::Some(err)
    }
}

fn start_daemon() -> Child {
    log("Starting daemon");

    if let Some(user_home) = env::home_dir() {
        let mut jgrab_jar: PathBuf = user_home;
        jgrab_jar.push(".jgrab");
        jgrab_jar.push("jgrab.jar");

        if jgrab_jar.as_path().is_file() {
            let cmd = Command::new("java")
                .arg("-jar")
                .arg(jgrab_jar.into_os_string().into_string().unwrap())
                .arg("--daemon")
                .spawn();

            match cmd {
                Ok(child) => {
                    log(&format!("Daemon started, pid={}", child.id()));
                    child
                }
                Err(err) => error(&err.to_string())
            }
        } else {
            error("The JGrab jar is not installed! Please install it as explained \
                   in https://github.com/renatoathaydes/jgrab");
        }
    } else {
        error("user.home could not be found, making it impossible to start the JGrab Daemon");
    }
}

fn check_status(child: &mut Child) {
    let timeout = Duration::from_secs(1);

    match child.wait_timeout(timeout) {
        Ok(Some(status)) => error(&format!(
            "The JGrab daemon has died prematurely, exit code was {}", status)),
        Ok(None) => {
            // give time for the socket server to become active
            sleep(Duration::from_secs(1));
        }
        Err(e) => error(&format!(
            "unable to wait for JGrab daemon process status: {}", e)),
    }
}

fn log(message: &str) {
    println!("=== JGrab Client {} ===", message)
}

fn usage_error(message: &str) -> ! {
    println!("### {} ###\n\n{}", message, JGRAB_USAGE);
    exit(2)
}

fn error(message: &str) -> ! {
    println!("### JGrab Client Error - {} ###", message);
    exit(1)
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use structopt::StructOpt;

type Chemical = String;

#[derive(Debug, Clone)]
struct Reaction {
    inputs: HashMap<Chemical, isize>,
    output: Chemical,
    output_count: isize,
}

fn dfs_order<T, F, IterT>(initial: T, next: F) -> Vec<T>
where
    T: Eq + Clone + std::hash::Hash,
    F: Fn(&T) -> IterT,
    IterT: IntoIterator<Item = T>,
{
    let mut stack = vec![initial];
    let mut visited = HashSet::new();
    let mut results = Vec::new();
    while let Some(node) = stack.pop() {
        if visited.contains(&node) {
            // our second time visiting, so we've already processed all of the children nodes
            results.push(node);
            continue;
        }
        visited.insert(node.clone());
        stack.extend(
            next(&node)
                .into_iter()
                .filter(|node| !visited.contains(node)),
        );
        stack.push(node);
    }
    results
}

fn part1(input: &[Reaction]) -> isize {
    // assumption: all outputs are unique. But let's check that.
    let endings: HashSet<_> = input.iter().map(|rxn| rxn.output.clone()).collect();
    assert_eq!(input.len(), endings.len());
    let cookbook: HashMap<_, _> = input
        .iter()
        .cloned()
        .map(|rxn| (rxn.output, (rxn.inputs, rxn.output_count)))
        .collect();

    let mut ore_count = 0;
    let mut stack = vec![("FUEL".to_string(), 1)];
    while let Some((output, needed)) = stack.pop() {
        dbg!(&output);
        dbg!(needed);
        assert!(needed > 0);
        if output == "ORE" {
            ore_count += needed;
            continue;
        }
        let (ref ingredients, output_count) = cookbook[&output];
        let mut multiplier = needed / output_count;
        if needed % output_count != 0 {
            multiplier += 1;
        }
        for (ingredient, count) in ingredients.iter() {
            stack.push((ingredient.clone(), count * multiplier))
        }
    }
    ore_count
}

fn main() {
    let input = parser::parse(
        &std::fs::read_to_string(Opt::from_args().input).expect("error reading file"),
    );
    println!("Part 1: {}", part1(&input));
}

mod parser {
    use super::{Chemical, Reaction};
    use nom::bytes::complete::tag;
    use nom::character::complete::{alpha1, digit1, line_ending};
    use nom::combinator::{map, map_res};
    use nom::multi::{separated_list, separated_nonempty_list};
    use nom::sequence::separated_pair;
    use std::collections::HashMap;

    type IResult<'a, O> = nom::IResult<&'a str, O>;

    pub(super) fn parse(input: &str) -> Vec<Reaction> {
        let (rest, result) = separated_list(line_ending, reaction)(input)
            .unwrap_or_else(|err| panic!("Parser failure: {}", err));
        assert!(
            ["", "\n", "\r\n"].contains(&rest),
            "Unexpected trailing input: {:?}",
            rest
        );
        result
    }

    fn reaction(input: &str) -> IResult<Reaction> {
        map(
            separated_pair(chemical_inputs, tag(" => "), chemical_count),
            |(inputs, (output, output_count))| Reaction {
                inputs,
                output,
                output_count,
            },
        )(input)
    }

    fn chemical_inputs(input: &str) -> IResult<HashMap<Chemical, isize>> {
        let (rest, counts) = separated_nonempty_list(tag(", "), chemical_count)(input)?;
        Ok((rest, counts.into_iter().collect()))
    }

    fn chemical_count(input: &str) -> IResult<(Chemical, isize)> {
        let (rest, (count, chem)) =
            separated_pair(map_res(digit1, |s: &str| s.parse()), tag(" "), alpha1)(input)?;
        Ok((rest, (chem.into(), count)))
    }
}

#[derive(StructOpt)]
struct Opt {
    #[structopt(parse(from_os_str))]
    input: PathBuf,
}

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

    #[test]
    fn test_part1() {
        assert_eq!(part1(&parser::parse(include_str!("../examples/1.txt"))), 31);
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/2.txt"))),
            165
        );
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/3.txt"))),
            13_312
        );
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/4.txt"))),
            180_697
        );
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/5.txt"))),
            2_210_736
        );
    }
}
<commit_msg>2019 day 14 WiP<commit_after>use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use structopt::StructOpt;

type Chemical = String;

#[derive(Debug, Clone)]
struct Reaction {
    inputs: HashMap<Chemical, isize>,
    output: Chemical,
    output_count: isize,
}

fn dfs_order<T, F, IterT>(initial: T, next: F) -> Vec<T>
where
    T: Eq + Clone + std::hash::Hash + std::fmt::Debug,
    F: Fn(&T) -> IterT,
    IterT: IntoIterator<Item = T>,
{
    let mut stack = vec![(initial, false)];
    let mut visited = HashSet::new();
    let mut results = Vec::new();
    while let Some((node, visited_as_parent)) = stack.pop() {
        if visited_as_parent {
            results.push(node);
            continue;
        }
        if visited.contains(&node) {
            continue;
        }
        visited.insert(node.clone());
        stack.push((node.clone(), true));
        stack.extend(
            next(&node)
                .into_iter()
                .filter(|node| !visited.contains(node))
                .map(|node| (node, false)),
        );
    }
    results
}

fn part1(input: &[Reaction]) -> isize {
    // assumption: all outputs are unique. But let's check that.
    let endings: HashSet<_> = input.iter().map(|rxn| rxn.output.clone()).collect();
    assert_eq!(input.len(), endings.len());
    let cookbook: HashMap<_, _> = input
        .iter()
        .cloned()
        .map(|rxn| (rxn.output, (rxn.inputs, rxn.output_count)))
        .collect();

    let mut ore_count = 0;
    let mut stack = vec![("FUEL".to_string(), 1)];
    while let Some((output, needed)) = stack.pop() {
        dbg!(&output);
        dbg!(needed);
        assert!(needed > 0);
        if output == "ORE" {
            ore_count += needed;
            continue;
        }
        let (ref ingredients, output_count) = cookbook[&output];
        let mut multiplier = needed / output_count;
        if needed % output_count != 0 {
            multiplier += 1;
        }
        for (ingredient, count) in ingredients.iter() {
            stack.push((ingredient.clone(), count * multiplier))
        }
    }
    ore_count
}

fn main() {
    let input = parser::parse(
        &std::fs::read_to_string(Opt::from_args().input).expect("error reading file"),
    );
    println!("Part 1: {}", part1(&input));
}

mod parser {
    use super::{Chemical, Reaction};
    use nom::bytes::complete::tag;
    use nom::character::complete::{alpha1, digit1, line_ending};
    use nom::combinator::{map, map_res};
    use nom::multi::{separated_list, separated_nonempty_list};
    use nom::sequence::separated_pair;
    use std::collections::HashMap;

    type IResult<'a, O> = nom::IResult<&'a str, O>;

    pub(super) fn parse(input: &str) -> Vec<Reaction> {
        let (rest, result) = separated_list(line_ending, reaction)(input)
            .unwrap_or_else(|err| panic!("Parser failure: {}", err));
        assert!(
            ["", "\n", "\r\n"].contains(&rest),
            "Unexpected trailing input: {:?}",
            rest
        );
        result
    }

    fn reaction(input: &str) -> IResult<Reaction> {
        map(
            separated_pair(chemical_inputs, tag(" => "), chemical_count),
            |(inputs, (output, output_count))| Reaction {
                inputs,
                output,
                output_count,
            },
        )(input)
    }

    fn chemical_inputs(input: &str) -> IResult<HashMap<Chemical, isize>> {
        let (rest, counts) = separated_nonempty_list(tag(", "), chemical_count)(input)?;
        Ok((rest, counts.into_iter().collect()))
    }

    fn chemical_count(input: &str) -> IResult<(Chemical, isize)> {
        let (rest, (count, chem)) =
            separated_pair(map_res(digit1, |s: &str| s.parse()), tag(" "), alpha1)(input)?;
        Ok((rest, (chem.into(), count)))
    }
}

#[derive(StructOpt)]
struct Opt {
    #[structopt(parse(from_os_str))]
    input: PathBuf,
}

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

    #[test]
    fn test_part1() {
        assert_eq!(part1(&parser::parse(include_str!("../examples/1.txt"))), 31);
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/2.txt"))),
            165
        );
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/3.txt"))),
            13_312
        );
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/4.txt"))),
            180_697
        );
        assert_eq!(
            part1(&parser::parse(include_str!("../examples/5.txt"))),
            2_210_736
        );
    }

    #[test]
    fn test_dfs_order() {
        let graph: HashMap<_, _> = vec![
            ('a', vec!['b', 'c']),
            ('b', vec!['c']),
            ('c', vec!['d', 'e']),
            ('d', vec!['b']),
            ('e', vec![]),
        ]
        .into_iter()
        .collect();
        assert_eq!(
            dfs_order('a', |ch| graph[ch].iter().cloned()),
            vec!['e', 'b', 'd', 'c', 'a']
        )
    }
}
<|endoftext|>