<commit_before>//! Contains all the clientbound packets
//!
//! See the clientbound sections on http://wiki.vg/Protocol for information
//! about all the available packets.
//!
//! The goal is also to add a bunch of useful helper functions to the packets,
//! if you feel such a function is missing, open an issue.

use read::*;
use {ClientState, u128};

use std::collections::BTreeMap;
use std::io::Read;
use std::io;
use std::ops::Deref;

/* See packets.clj for information about this include */
include!("./.client_recv.generated.rs");

/* Now come the manual definitions for the edge cases that don't fit into
 * packets.clj's code generation */

impl Statistics {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let count = read_varint(r)?;
        let mut tmp = BTreeMap::new();
        for _ in 0..count {
            tmp.insert(read_String(r)?, read_varint(r)?);
        }
        Ok(ClientboundPacket::Statistics(Statistics {
            values: tmp,
}))
}
}

impl ClientboundTabComplete {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let count = read_varint(r)?;
        let mut tmp = Vec::with_capacity(count as usize);
        for _ in 0..count {
            tmp.push(read_String(r)?);
        }
        Ok(ClientboundPacket::ClientboundTabComplete(ClientboundTabComplete {
            matches: tmp,
        }))
    }
}

impl MultiBlockChange {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let chunk_x = read_i32(r)?;
        let chunk_z = read_i32(r)?;
        let count = read_varint(r)?;
        let mut tmp: Vec<(u8, u8, u8, i32)> = Vec::with_capacity(count as usize);
        for _ in 0..count {
            let hori_pos = read_u8(r)?;
            let y = read_u8(r)?;
            let block_state = read_varint(r)?;
            let x = (hori_pos & 0xF0) >> 4;
            let z = hori_pos & 0x0F;
            tmp.push((x, y, z, block_state));
        }
        Ok(ClientboundPacket::MultiBlockChange(MultiBlockChange {
            chunk_x: chunk_x,
            chunk_z: chunk_z,
            changes: tmp,
        }))
    }
}

impl OpenWindow {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let window_id = read_u8(r)?;
        let window_type = read_String(r)?;
        let window_title = read_String(r)?;
        let number_of_slots = read_u8(r)?;
        let entity_id = match window_type.deref() {
            "EntityHorse" => Some(read_i32(r)?),
            _ => None,
        };

        Ok(ClientboundPacket::OpenWindow(OpenWindow {
            window_id: window_id,
            window_type: window_type,
            window_title: window_title,
            number_of_slots: number_of_slots,
            entity_id: entity_id,
        }))
    }
}

impl Explosion {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let x = read_f32(r)?;
        let y = read_f32(r)?;
        let z = read_f32(r)?;
        let radius = read_f32(r)?;
        let count = read_i32(r)?;
        let mut tmp: Vec<(i8, i8, i8)> = Vec::with_capacity(count as usize);
        for _ in 0..count {
            tmp.push((read_i8(r)?, read_i8(r)?, read_i8(r)?));
        }
        let motion_x = read_f32(r)?;
        let motion_y = read_f32(r)?;
        let motion_z = read_f32(r)?;
        Ok(ClientboundPacket::Explosion(Explosion {
            x: x,
            y: y,
            z: z,
            radius: radius,
            affected_blocks: tmp,
            motion_x: motion_x,
            motion_y: motion_y,
            motion_z: motion_z,
        }))
    }
}

impl Particle {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let particle_id = read_i32(r)?;
        let long_distance = read_bool(r)?;
        let x = read_f32(r)?;
        let y = read_f32(r)?;
        let z = read_f32(r)?;
        let offset_x = read_f32(r)?;
        let offset_y = read_f32(r)?;
        let offset_z = read_f32(r)?;
        let particle_data = read_f32(r)?;
        let count = read_i32(r)?;
        let id = match particle_id {
            36 | 37 | 38 => Some(read_varint(r)?),
            _ => None,
        };
        let crack_data = match particle_id {
            36 | 37 => Some(read_varint(r)?),
            _ => None,
        };
        Ok(ClientboundPacket::Particle(Particle {
            particle_id: particle_id,
            use_long_distance: long_distance,
            x: x,
            y: y,
            z: z,
            offset_x: offset_x,
            offset_y: offset_y,
            offset_z: offset_z,
            particle_data: particle_data,
            count: count,
            id: id,
            crack_data: crack_data,
        }))
    }
}

impl CombatEvent {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let event = read_varint(r)?;
        let (duration_playerid, entity_id, message) = match event {
            0 => (None, None, None),
            1 => (Some(read_varint(r)?), Some(read_i32(r)?), None),
            2 => {
                (Some(read_varint(r)?),
                Some(read_i32(r)?),
                Some(read_String(r)?))
            },
            _ => return io_error!("Invalid event in CombatEvent"),
        };
        Ok(ClientboundPacket::CombatEvent(CombatEvent {
            event: event,
            duration_playerid: duration_playerid,
            entity_id: entity_id,
            message: message,
        }))
    }
}

impl ScoreboardObjective {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let name = read_String(r)?;
        let mode = read_u8(r)?;
        let (value, objective_type) = match mode {
            0 | 2 => (Some(read_String(r)?), Some(read_String(r)?)),
            _ => (None, None),
        };
        Ok(ClientboundPacket::ScoreboardObjective(ScoreboardObjective {
            name: name,
            mode: mode,
            value: value,
            objective_type: objective_type,
        }))
    }
}

impl UpdateScore {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let name = read_String(r)?;
        let action = read_u8(r)?;
        let objective_name = read_String(r)?;
        let value = match action {
            1 => Some(read_varint(r)?),
            _ => None,
        };
        Ok(ClientboundPacket::UpdateScore(UpdateScore {
            name: name,
            action: action,
            objective_name: objective_name,
            value: value,
        }))
    }
}

impl Title {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let action = read_varint(r)?;
        let text = match action {
            0 | 1 | 2 => Some(read_String(r)?),
            _ => None,
        };
        let times = match action {
            3 => Some((read_i32(r)?, read_i32(r)?, read_i32(r)?)),
            _ => None,
        };
        Ok(ClientboundPacket::Title(Title {
            action: action,
            text: text,
            times: times,
        }))
    }
}

<commit_msg>Add convenience functions for the bitmask in PlayerAbilities<commit_after>//! Contains all the clientbound packets
//!
//! See the clientbound sections on http://wiki.vg/Protocol for information
//! about all the available packets.
//!
//! The goal is also to add a bunch of useful helper functions to the packets,
//! if you feel such a function is missing, open an issue.

use read::*;
use {ClientState, u128};

use std::collections::BTreeMap;
use std::io::Read;
use std::io;
use std::ops::Deref;

/* See packets.clj for information about this include */
include!("./.client_recv.generated.rs");

/* Now come the manual definitions for the edge cases that don't fit into
 * packets.clj's code generation */

impl Statistics {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let count = read_varint(r)?;
        let mut tmp = BTreeMap::new();
        for _ in 0..count {
            tmp.insert(read_String(r)?, read_varint(r)?);
        }
        Ok(ClientboundPacket::Statistics(Statistics {
            values: tmp,
}))
}
}

impl ClientboundTabComplete {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let count = read_varint(r)?;
        let mut tmp = Vec::with_capacity(count as usize);
        for _ in 0..count {
            tmp.push(read_String(r)?);
        }
        Ok(ClientboundPacket::ClientboundTabComplete(ClientboundTabComplete {
            matches: tmp,
        }))
    }
}

impl MultiBlockChange {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let chunk_x = read_i32(r)?;
        let chunk_z = read_i32(r)?;
        let count = read_varint(r)?;
        let mut tmp: Vec<(u8, u8, u8, i32)> = Vec::with_capacity(count as usize);
        for _ in 0..count {
            let hori_pos = read_u8(r)?;
            let y = read_u8(r)?;
            let block_state = read_varint(r)?;
            let x = (hori_pos & 0xF0) >> 4;
            let z = hori_pos & 0x0F;
            tmp.push((x, y, z, block_state));
        }
        Ok(ClientboundPacket::MultiBlockChange(MultiBlockChange {
            chunk_x: chunk_x,
            chunk_z: chunk_z,
            changes: tmp,
        }))
    }
}

impl OpenWindow {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let window_id = read_u8(r)?;
        let window_type = read_String(r)?;
        let window_title = read_String(r)?;
        let number_of_slots = read_u8(r)?;
        let entity_id = match window_type.deref() {
            "EntityHorse" => Some(read_i32(r)?),
            _ => None,
        };

        Ok(ClientboundPacket::OpenWindow(OpenWindow {
            window_id: window_id,
            window_type: window_type,
            window_title: window_title,
            number_of_slots: number_of_slots,
            entity_id: entity_id,
        }))
    }
}

impl Explosion {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let x = read_f32(r)?;
        let y = read_f32(r)?;
        let z = read_f32(r)?;
        let radius = read_f32(r)?;
        let count = read_i32(r)?;
        let mut tmp: Vec<(i8, i8, i8)> = Vec::with_capacity(count as usize);
        for _ in 0..count {
            tmp.push((read_i8(r)?, read_i8(r)?, read_i8(r)?));
        }
        let motion_x = read_f32(r)?;
        let motion_y = read_f32(r)?;
        let motion_z = read_f32(r)?;
        Ok(ClientboundPacket::Explosion(Explosion {
            x: x,
            y: y,
            z: z,
            radius: radius,
            affected_blocks: tmp,
            motion_x: motion_x,
            motion_y: motion_y,
            motion_z: motion_z,
        }))
    }
}

impl Particle {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let particle_id = read_i32(r)?;
        let long_distance = read_bool(r)?;
        let x = read_f32(r)?;
        let y = read_f32(r)?;
        let z = read_f32(r)?;
        let offset_x = read_f32(r)?;
        let offset_y = read_f32(r)?;
        let offset_z = read_f32(r)?;
        let particle_data = read_f32(r)?;
        let count = read_i32(r)?;
        let id = match particle_id {
            36 | 37 | 38 => Some(read_varint(r)?),
            _ => None,
        };
        let crack_data = match particle_id {
            36 | 37 => Some(read_varint(r)?),
            _ => None,
        };
        Ok(ClientboundPacket::Particle(Particle {
            particle_id: particle_id,
            use_long_distance: long_distance,
            x: x,
            y: y,
            z: z,
            offset_x: offset_x,
            offset_y: offset_y,
            offset_z: offset_z,
            particle_data: particle_data,
            count: count,
            id: id,
            crack_data: crack_data,
        }))
    }
}

impl CombatEvent {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let event = read_varint(r)?;
        let (duration_playerid, entity_id, message) = match event {
            0 => (None, None, None),
            1 => (Some(read_varint(r)?), Some(read_i32(r)?), None),
            2 => {
                (Some(read_varint(r)?),
                Some(read_i32(r)?),
                Some(read_String(r)?))
            },
            _ => return io_error!("Invalid event in CombatEvent"),
        };
        Ok(ClientboundPacket::CombatEvent(CombatEvent {
            event: event,
            duration_playerid: duration_playerid,
            entity_id: entity_id,
            message: message,
        }))
    }
}

impl ScoreboardObjective {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let name = read_String(r)?;
        let mode = read_u8(r)?;
        let (value, objective_type) = match mode {
            0 | 2 => (Some(read_String(r)?), Some(read_String(r)?)),
            _ => (None, None),
        };
        Ok(ClientboundPacket::ScoreboardObjective(ScoreboardObjective {
            name: name,
            mode: mode,
            value: value,
            objective_type: objective_type,
        }))
    }
}

impl UpdateScore {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let name = read_String(r)?;
        let action = read_u8(r)?;
        let objective_name = read_String(r)?;
        let value = match action {
            1 => Some(read_varint(r)?),
            _ => None,
        };
        Ok(ClientboundPacket::UpdateScore(UpdateScore {
            name: name,
            action: action,
            objective_name: objective_name,
            value: value,
        }))
    }
}

impl Title {
    fn new<R: Read>(r: &mut R) -> io::Result<ClientboundPacket> {
        let action = read_varint(r)?;
        let text = match action {
            0 | 1 | 2 => Some(read_String(r)?),
            _ => None,
        };
        let times = match action {
            3 => Some((read_i32(r)?, read_i32(r)?, read_i32(r)?)),
            _ => None,
        };
        Ok(ClientboundPacket::Title(Title {
            action: action,
            text: text,
            times: times,
        }))
    }
}

impl PlayerAbilities {
    /// Get whether the player is invulnerable
    pub fn is_invulnerable(&self) -> bool {
        (self.flags & 0x01) != 0
    }
    /// Get whether the player is flying
    pub fn is_flying(&self) -> bool {
        (self.flags & 0x02) != 0
    }
    /// Get whether the player is allowed to fly
    pub fn allow_flying(&self) -> bool {
        (self.flags & 0x04) != 0
    }
    /// Get whether player is in creative mode
    pub fn is_creative(&self) -> bool {
        (self.flags & 0x08) != 0
    }
}

<|endoftext|>


<commit_before>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/

use game::{Move, Position, Side};
use nimstring;
use std::io::{self, BufRead};
use std::fs::File;
use regex::{Regex, Captures};

#[derive(PartialEq)]
#[derive(Debug)]
enum Command {
    MakeMove(Move),
    UndoMove(Move),
    CalcNimstringValue,
    PrintHelp,
    Quit,
}

impl Command {
    fn execute(self: &Command, pos: &mut Position) {
        match self {
            &Command::MakeMove(m) => {
                if pos.is_legal_move(m.x, m.y, m.side) {
                    pos.make_move(m.x, m.y, m.side);
                }
                else {
                    println!("Not a legal move: {}", m);
                }
            },
            &Command::UndoMove(m) => { pos.undo_move(m.x, m.y, m.side); },
            &Command::CalcNimstringValue => {
                let (val, per_move) = nimstring::calc_value_with_moves(pos);
                println!("Position value is {}", val);
                let mut moves: Vec<&Move> = per_move.keys().collect();
                moves.sort_by(|a, b| a.x.cmp(&b.x).then(a.y.cmp(&b.y)).then(a.side.cmp(&b.side)));
                for &m in &moves {
                    println!("{} {}", m, per_move.get(m).unwrap());
                }
            },
            &Command::PrintHelp => { print_help(); },
            &Command::Quit => { println!("Bye bye!"); },
        }
    }
}

fn print_help() {
    println!("Available commands:");
    println!("x y t/l/b/r - make move (x,y) top/left/bottom/right");
    println!("u x y t/l/b/r - undo move (x,y) top/left/bottom/right");
    println!("nv - calculate Nimstring value of current position");
    println!("help - print this help message");
    println!("quit/exit - exit program");
}

fn parse_side(side_s: &str) -> Option<Side> {
    if side_s == "l" || side_s == "left" { Some(Side::Left) }
    else if side_s == "r" || side_s == "right" { Some(Side::Right) }
    else if side_s == "t" || side_s == "top" { Some(Side::Top) }
    else if side_s == "b" || side_s == "bottom" { Some(Side::Bottom) }
    else { None }
}

fn parse_move(caps: Captures) -> Result<Move, String> {
    let x = caps[1].parse::<usize>().unwrap();
    let y = caps[2].parse::<usize>().unwrap();
    let side_s = caps[3].to_string();
    match parse_side(&side_s) {
        Some(side) => Ok(Move{x: x, y: y, side: side}),
        None => Err(format!("Unrecognised side: [{}]", side_s))
    }
}

fn parse_command(input: &str) -> Result<Command, String> {
    let input = input.to_lowercase();
    let move_re = Regex::new(r"^(\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::MakeMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    let undo_move_re = Regex::new(r"^[uU] (\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = undo_move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::UndoMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    if "nv" == input {
        return Ok(Command::CalcNimstringValue);
    }
    if "help" == input {
        return Ok(Command::PrintHelp);
    }
    if "exit" == input || "quit" == input {
        return Ok(Command::Quit);
    }
    Err("Unsupported command".to_string())
}

fn get_next_command() -> Command {
    loop {
        let mut input = String::new();
        if let Err(error) = io::stdin().read_line(&mut input) {
            println!("Error reading from standard input: {}", error);
            continue;
        }
        let input = input.trim();
        match parse_command(&input) {
            Ok(command) => return command,
            Err(error) => {
                println!("Cannot execute [{}]: {}", input, error);
                println!("For help, try 'help'");
            }
        }
    }
}

fn main_loop_from(pos: &mut Position) {
    loop {
        println!("{}", pos);
        let command = get_next_command();
        command.execute(pos);
        if command == Command::Quit {
            break;
        }
        println!();
    }
}

// Enter the main loop of the CLI from the start of the game
pub fn main_loop_start(width: usize, height: usize) {
    main_loop_from(&mut Position::new_game(width, height));
}

// Execute a given file of commands (which must have the dimensions of the position on the first line)
// and then enter the CLI main loop.
pub fn main_loop_file(filename: &str) {
    let f = File::open(filename).expect(&format!("Could not open file [{}]", filename));
    let reader = io::BufReader::new(f);
    let mut lines = reader.lines();
    let size_spec = lines.next().expect("Empty file").expect("Could not read board size from first line");
    let size_re = Regex::new(r"^(\d+) (\d+)$").unwrap();
    let size_caps = size_re.captures(&size_spec).expect(&format!("Could not read board size from [{}]", size_spec));
    let width = size_caps[1].parse::<usize>().unwrap();
    let height = size_caps[2].parse::<usize>().unwrap();
    let mut pos = Position::new_game(width, height);
    for line in lines {
        let line = line.expect("Could not read line from file");
        match parse_command(&line) {
            Ok(command) => command.execute(&mut pos),
            Err(error) => panic!("Cannot execute [{}]: {}", line, error),
        }
    }
    main_loop_from(&mut pos);
}

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

    #[test]
    fn parse_make_move_cmd() {
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 b").unwrap());
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 Bottom").unwrap());
    }

    #[test]
    fn parse_undo_move_cmd() {
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 l").unwrap());
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 Left").unwrap());
    }

    #[test]
    fn parse_nimstring_value_cmd() {
        assert_eq!(Command::CalcNimstringValue, parse_command("nv").unwrap());
    }

    #[test]
    fn parse_help_cmd() {
        assert_eq!(Command::PrintHelp, parse_command("help").unwrap());
    }

    #[test]
    fn parse_exit_cmd() {
        assert_eq!(Command::Quit, parse_command("quit").unwrap());
        assert_eq!(Command::Quit, parse_command("exit").unwrap());
    }
}
<commit_msg>Report moves left-right then top-bottom<commit_after>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/

use game::{Move, Position, Side};
use nimstring;
use std::io::{self, BufRead};
use std::fs::File;
use regex::{Regex, Captures};

#[derive(PartialEq)]
#[derive(Debug)]
enum Command {
    MakeMove(Move),
    UndoMove(Move),
    CalcNimstringValue,
    PrintHelp,
    Quit,
}

impl Command {
    fn execute(self: &Command, pos: &mut Position) {
        match self {
            &Command::MakeMove(m) => {
                if pos.is_legal_move(m.x, m.y, m.side) {
                    pos.make_move(m.x, m.y, m.side);
                }
                else {
                    println!("Not a legal move: {}", m);
                }
            },
            &Command::UndoMove(m) => { pos.undo_move(m.x, m.y, m.side); },
            &Command::CalcNimstringValue => {
                let (val, per_move) = nimstring::calc_value_with_moves(pos);
                println!("Position value is {}", val);
                let mut moves: Vec<&Move> = per_move.keys().collect();
                moves.sort_by(|a, b| a.y.cmp(&b.y).then(a.x.cmp(&b.x)).then(a.side.cmp(&b.side)));
                for &m in &moves {
                    println!("{} {}", m, per_move.get(m).unwrap());
                }
            },
            &Command::PrintHelp => { print_help(); },
            &Command::Quit => { println!("Bye bye!"); },
        }
    }
}

fn print_help() {
    println!("Available commands:");
    println!("x y t/l/b/r - make move (x,y) top/left/bottom/right");
    println!("u x y t/l/b/r - undo move (x,y) top/left/bottom/right");
    println!("nv - calculate Nimstring value of current position");
    println!("help - print this help message");
    println!("quit/exit - exit program");
}

fn parse_side(side_s: &str) -> Option<Side> {
    if side_s == "l" || side_s == "left" { Some(Side::Left) }
    else if side_s == "r" || side_s == "right" { Some(Side::Right) }
    else if side_s == "t" || side_s == "top" { Some(Side::Top) }
    else if side_s == "b" || side_s == "bottom" { Some(Side::Bottom) }
    else { None }
}

fn parse_move(caps: Captures) -> Result<Move, String> {
    let x = caps[1].parse::<usize>().unwrap();
    let y = caps[2].parse::<usize>().unwrap();
    let side_s = caps[3].to_string();
    match parse_side(&side_s) {
        Some(side) => Ok(Move{x: x, y: y, side: side}),
        None => Err(format!("Unrecognised side: [{}]", side_s))
    }
}

fn parse_command(input: &str) -> Result<Command, String> {
    let input = input.to_lowercase();
    let move_re = Regex::new(r"^(\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::MakeMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    let undo_move_re = Regex::new(r"^[uU] (\d+) (\d+) ([a-zA-Z]+)$").unwrap();
    if let Some(caps) = undo_move_re.captures(&input) {
        match parse_move(caps) {
            Ok(m) => return Ok(Command::UndoMove(m)),
            Err(e) => return Err(format!("Cannot extract move from [{}]: {}", input, e))
        }
    }
    if "nv" == input {
        return Ok(Command::CalcNimstringValue);
    }
    if "help" == input {
        return Ok(Command::PrintHelp);
    }
    if "exit" == input || "quit" == input {
        return Ok(Command::Quit);
    }
    Err("Unsupported command".to_string())
}

fn get_next_command() -> Command {
    loop {
        let mut input = String::new();
        if let Err(error) = io::stdin().read_line(&mut input) {
            println!("Error reading from standard input: {}", error);
            continue;
        }
        let input = input.trim();
        match parse_command(&input) {
            Ok(command) => return command,
            Err(error) => {
                println!("Cannot execute [{}]: {}", input, error);
                println!("For help, try 'help'");
            }
        }
    }
}

fn main_loop_from(pos: &mut Position) {
    loop {
        println!("{}", pos);
        let command = get_next_command();
        command.execute(pos);
        if command == Command::Quit {
            break;
        }
        println!();
    }
}

// Enter the main loop of the CLI from the start of the game
pub fn main_loop_start(width: usize, height: usize) {
    main_loop_from(&mut Position::new_game(width, height));
}

// Execute a given file of commands (which must have the dimensions of the position on the first line)
// and then enter the CLI main loop.
pub fn main_loop_file(filename: &str) {
    let f = File::open(filename).expect(&format!("Could not open file [{}]", filename));
    let reader = io::BufReader::new(f);
    let mut lines = reader.lines();
    let size_spec = lines.next().expect("Empty file").expect("Could not read board size from first line");
    let size_re = Regex::new(r"^(\d+) (\d+)$").unwrap();
    let size_caps = size_re.captures(&size_spec).expect(&format!("Could not read board size from [{}]", size_spec));
    let width = size_caps[1].parse::<usize>().unwrap();
    let height = size_caps[2].parse::<usize>().unwrap();
    let mut pos = Position::new_game(width, height);
    for line in lines {
        let line = line.expect("Could not read line from file");
        match parse_command(&line) {
            Ok(command) => command.execute(&mut pos),
            Err(error) => panic!("Cannot execute [{}]: {}", line, error),
        }
    }
    main_loop_from(&mut pos);
}

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

    #[test]
    fn parse_make_move_cmd() {
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 b").unwrap());
        assert_eq!(Command::MakeMove(Move{x: 3, y: 5, side: Side::Bottom}), parse_command("3 5 Bottom").unwrap());
    }

    #[test]
    fn parse_undo_move_cmd() {
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 l").unwrap());
        assert_eq!(Command::UndoMove(Move{x: 8, y: 6, side: Side::Left}), parse_command("u 8 6 Left").unwrap());
    }

    #[test]
    fn parse_nimstring_value_cmd() {
        assert_eq!(Command::CalcNimstringValue, parse_command("nv").unwrap());
    }

    #[test]
    fn parse_help_cmd() {
        assert_eq!(Command::PrintHelp, parse_command("help").unwrap());
    }

    #[test]
    fn parse_exit_cmd() {
        assert_eq!(Command::Quit, parse_command("quit").unwrap());
        assert_eq!(Command::Quit, parse_command("exit").unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::fmt::{self, Display};
use std::ops::{BitAnd, BitOr};

use serde::{Deserialize, Serialize};

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct GuestAddress(pub u64);

impl GuestAddress {
    /// Returns the offset from this address to the given base address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use vm_memory::GuestAddress;
    ///   let base = GuestAddress(0x100);
    ///   let addr = GuestAddress(0x150);
    ///   assert_eq!(addr.offset_from(base), 0x50u64);
    /// ```
    pub fn offset_from(self, base: GuestAddress) -> u64 {
        self.0 - base.0
    }

    /// Returns the address as a u64 offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    pub fn offset(self) -> u64 {
        self.0
    }

    /// Returns the result of the add or None if there is overflow.
    pub fn checked_add(self, other: u64) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    pub fn unchecked_add(self, offset: u64) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    pub fn checked_sub(self, other: u64) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }

    /// Returns the bitwise and of the address with the given mask.
    pub fn mask(self, mask: u64) -> GuestAddress {
        GuestAddress(self.0 & mask as u64)
    }
}

impl BitAnd<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 & other as u64)
    }
}

impl BitOr<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 | other as u64)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for GuestAddress {
    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Display for GuestAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#x}", self.0)
    }
}

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    #[allow(clippy::eq_op)]
    #[allow(clippy::nonminimal_bool)]
    fn cmp() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x301);
        assert!(a < b);
        assert!(b > a);
        assert!(!(a < a));
        assert!(a >= a);
    }

    #[test]
    fn mask() {
        let a = GuestAddress(0x5050);
        assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
        assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffffffffffffff55);
        assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }
}
<commit_msg>vm_memory: add GuestAddress::align<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Represents an address in the guest's memory space.

use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use std::fmt::{self, Display};
use std::ops::{BitAnd, BitOr};

use serde::{Deserialize, Serialize};

/// Represents an Address in the guest's memory.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct GuestAddress(pub u64);

impl GuestAddress {
    /// Returns the offset from this address to the given base address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use vm_memory::GuestAddress;
    ///   let base = GuestAddress(0x100);
    ///   let addr = GuestAddress(0x150);
    ///   assert_eq!(addr.offset_from(base), 0x50u64);
    /// ```
    pub fn offset_from(self, base: GuestAddress) -> u64 {
        self.0 - base.0
    }

    /// Returns the address as a u64 offset from 0x0.
    /// Use this when a raw number is needed to pass to the kernel.
    pub fn offset(self) -> u64 {
        self.0
    }

    /// Returns the result of the add or None if there is overflow.
    pub fn checked_add(self, other: u64) -> Option<GuestAddress> {
        self.0.checked_add(other).map(GuestAddress)
    }

    /// Returns the result of the base address + the size.
    /// Only use this when `offset` is guaranteed not to overflow.
    pub fn unchecked_add(self, offset: u64) -> GuestAddress {
        GuestAddress(self.0 + offset)
    }

    /// Returns the result of the subtraction of None if there is underflow.
    pub fn checked_sub(self, other: u64) -> Option<GuestAddress> {
        self.0.checked_sub(other).map(GuestAddress)
    }

    /// Returns the bitwise and of the address with the given mask.
    pub fn mask(self, mask: u64) -> GuestAddress {
        GuestAddress(self.0 & mask as u64)
    }

    /// Returns the next highest address that is a multiple of `align`, or an unchanged copy of the
    /// address if it's already a multiple of `align`.  Returns None on overflow.
    ///
    /// `align` must be a power of 2.
    pub fn align(self, align: u64) -> Option<GuestAddress> {
        if align <= 1 {
            return Some(self);
        }
        self.checked_add(align - 1).map(|a| a & !(align - 1))
    }
}

impl BitAnd<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitand(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 & other as u64)
    }
}

impl BitOr<u64> for GuestAddress {
    type Output = GuestAddress;

    fn bitor(self, other: u64) -> GuestAddress {
        GuestAddress(self.0 | other as u64)
    }
}

impl PartialEq for GuestAddress {
    fn eq(&self, other: &GuestAddress) -> bool {
        self.0 == other.0
    }
}
impl Eq for GuestAddress {}

impl Ord for GuestAddress {
    fn cmp(&self, other: &GuestAddress) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl PartialOrd for GuestAddress {
    fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Display for GuestAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:#x}", self.0)
    }
}

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

    #[test]
    fn equals() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x300);
        let c = GuestAddress(0x301);
        assert_eq!(a, b);
        assert_eq!(b, a);
        assert_ne!(a, c);
        assert_ne!(c, a);
    }

    #[test]
    #[allow(clippy::eq_op)]
    #[allow(clippy::nonminimal_bool)]
    fn cmp() {
        let a = GuestAddress(0x300);
        let b = GuestAddress(0x301);
        assert!(a < b);
        assert!(b > a);
        assert!(!(a < a));
        assert!(a >= a);
    }

    #[test]
    fn mask() {
        let a = GuestAddress(0x5050);
        assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
        assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
    }

    #[test]
    fn add_sub() {
        let a = GuestAddress(0x50);
        let b = GuestAddress(0x60);
        assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
        assert_eq!(0x10, b.offset_from(a));
    }

    #[test]
    fn checked_add_overflow() {
        let a = GuestAddress(0xffffffffffffff55);
        assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
        assert!(a.checked_add(0xf0).is_none());
    }

    #[test]
    fn align() {
        assert_eq!(GuestAddress(12345).align(0), Some(GuestAddress(12345)));
        assert_eq!(GuestAddress(12345).align(1), Some(GuestAddress(12345)));
        assert_eq!(GuestAddress(12345).align(2), Some(GuestAddress(12346)));
        assert_eq!(GuestAddress(0).align(4096), Some(GuestAddress(0)));
        assert_eq!(GuestAddress(1).align(4096), Some(GuestAddress(4096)));
        assert_eq!(GuestAddress(4095).align(4096), Some(GuestAddress(4096)));
        assert_eq!(GuestAddress(4096).align(4096), Some(GuestAddress(4096)));
        assert_eq!(GuestAddress(4097).align(4096), Some(GuestAddress(8192)));
        assert_eq!(
            GuestAddress(u64::MAX & !4095).align(4096),
            Some(GuestAddress(u64::MAX & !4095)),
        );
        assert_eq!(GuestAddress(u64::MAX).align(2), None);
    }
}
<|endoftext|>


<commit_before>// helper for transmutation, shown below.
type RustClosure = (int,int);

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

struct Handler<T, U:Copy> {
    handle: RustClosure
}

struct ProtectBlock<T, U:Copy> {
    cond: &Condition<T, U>,
    inner: RustClosure
}

struct Guard<T, U:Copy> {
    cond: &Condition<T,U>,
    prev: Option<@Handler<T, U>>,
    drop {
        match self.prev {
            None => (),
            Some(p) =>
            unsafe {
                debug!("Guard: popping handler from TLS");
                task::local_data::local_data_set(self.cond.key, p)
            }
        }
    }
}

struct HandleBlock<T, U:Copy> {
    pb: &ProtectBlock<T,U>,
    prev: Option<@Handler<T,U>>,
    handler: @Handler<T,U>,
    drop {
        unsafe {
            debug!("HandleBlock: pushing handler to TLS");
            let _g = Guard { cond: self.pb.cond,
                             prev: self.prev };
            task::local_data::local_data_set(self.pb.cond.key,
                                             self.handler);
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            let f : &fn() = ::cast::transmute(self.pb.inner);
            debug!("HandleBlock: invoking protected code");
            f();
            debug!("HandleBlock: returned from protected code");
        }
    }
}

struct Trap<T, U:Copy> {
    cond: &Condition<T,U>,
    handler: @Handler<T, U>
}

impl<T, U: Copy> ProtectBlock<T,U> {
    fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self<T,U> {
        unsafe {
            debug!("ProtectBlock.handle: setting up handler block");
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.cond.key);
            HandleBlock { pb: self,
                          prev: prev,
                          handler: @Handler{handle: *p} }
        }
    }
}

impl<T, U: Copy> Trap<T,U> {
    fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let prev = task::local_data::local_data_get(self.cond.key);
            let _g = Guard { cond: self.cond,
                             prev: prev };
            debug!("Trap: pushing handler to TLS");
            task::local_data::local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

impl<T, U: Copy>  Condition<T,U> {

    fn guard(&self, h: &self/fn(&T) ->U) -> Guard/&self<T,U> {
        unsafe {
            let prev = task::local_data::local_data_get(self.key);
            let g = Guard { cond: self, prev: prev };
            debug!("Guard: pushing handler to TLS");
            let p : *RustClosure = ::cast::transmute(&h);
            let h = @Handler{handle: *p};
            task::local_data::local_data_set(self.key, h);
            move g
        }
    }

    fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let h = @Handler{handle: *p};
            move Trap { cond: self, handler: h }
        }
    }

    fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self<T,U> {
        unsafe {
            // transmutation to avoid copying non-copyable, should
            // be fixable by tracking closure pointees in regionck.
            debug!("Condition.protect: setting up protected block");
            let p : *RustClosure = ::cast::transmute(&inner);
            ProtectBlock { cond: self,
                           inner: *p }
        }
    }

    fn raise(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_get(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
                    f(t)
                }
            }
        }
    }
}

#[cfg(test)]
fn sadness_key(_x: @Handler<int,int>) { }

#[cfg(test)]
fn trouble(i: int) {
    // Condition should work as a const, just limitations in consts.
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };
    debug!("trouble: raising conition");
    let j = sadness_condition.raise(&i);
    debug!("trouble: handler recovered with %d", j);
}

#[test]
fn test1() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut i = 10;

    let b = do sadness_condition.protect {
        debug!("test1: in protected block");
        trouble(1);
        trouble(2);
        trouble(3);
    };

    do b.handle |j| {
        debug!("test1: in handler");
        i += *j;
        i
    };

    assert i == 16;
}
#[cfg(test)]
fn nested_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_inner: in protected block");
        trouble(1);
    };

    do b.handle |_j| {
        debug!("nested_test_inner: in handler");
        inner_trapped = true;
        0
    };

    assert inner_trapped;
}

#[test]
fn nested_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let b = do sadness_condition.protect {
        debug!("nested_test_outer: in protected block");
        nested_test_inner();
        trouble(1);
    };

    do b.handle |_j| {
        debug!("nested_test_outer: in handler");
        outer_trapped = true;
        0
    };

    assert outer_trapped;
}

#[cfg(test)]
fn nested_guard_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    let _g = do sadness_condition.guard |_j| {
        debug!("nested_guard_test_inner: in handler");
        inner_trapped = true;
        0
    };

    debug!("nested_guard_test_inner: in protected block");
    trouble(1);

    assert inner_trapped;
}

#[test]
fn nested_guard_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    let _g = do sadness_condition.guard |_j| {
        debug!("nested_guard_test_outer: in handler");
        outer_trapped = true;
        0
    };

    debug!("nested_guard_test_outer: in protected block");
    nested_guard_test_inner();
    trouble(1);

    assert outer_trapped;
}

#[cfg(test)]
fn nested_trap_test_inner() {
    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut inner_trapped = false;

    do sadness_condition.trap(|_j| {
        debug!("nested_trap_test_inner: in handler");
        inner_trapped = true;
        0
    }).in {
        debug!("nested_trap_test_inner: in protected block");
        trouble(1);
    }

    assert inner_trapped;
}

#[test]
fn nested_trap_test_outer() {

    let sadness_condition : Condition<int,int> =
        Condition { key: sadness_key };

    let mut outer_trapped = false;

    do sadness_condition.trap(|_j| {
        debug!("nested_trap_test_outer: in handler");
        outer_trapped = true; 0
    }).in {
        debug!("nested_guard_test_outer: in protected block");
        nested_trap_test_inner();
        trouble(1);
    }

    assert outer_trapped;
}
<commit_msg>core: settle on the trap/in condition convention for now. Implement proper re-raising.<commit_after>// helper for transmutation, shown below.
type RustClosure = (int,int);
struct Handler<T, U:Copy> {
    handle: RustClosure,
    prev: Option<@Handler<T, U>>,
}

struct Condition<T, U:Copy> {
    key: task::local_data::LocalDataKey<Handler<T,U>>
}

impl<T, U: Copy>  Condition<T,U> {

    fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
        unsafe {
            let p : *RustClosure = ::cast::transmute(&h);
            let prev = task::local_data::local_data_get(self.key);
            let h = @Handler{handle: *p, prev: prev};
            move Trap { cond: self, handler: h }
        }
    }

    fn raise(t:&T) -> U {
        unsafe {
            match task::local_data::local_data_pop(self.key) {
                None => {
                    debug!("Condition.raise: found no handler");
                    fail
                }

                Some(handler) => {
                    debug!("Condition.raise: found handler");
                    match handler.prev {
                        None => (),
                        Some(hp) =>
                        task::local_data::local_data_set(self.key, hp)
                    }
                    let handle : &fn(&T) -> U =
                        ::cast::transmute(handler.handle);
                    let u = handle(t);
                    task::local_data::local_data_set(self.key,
                                                     handler);
                    move u
                }
            }
        }
    }
}

struct Trap<T, U:Copy> {
    cond: &Condition<T,U>,
    handler: @Handler<T, U>
}

impl<T, U: Copy> Trap<T,U> {
    fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
        unsafe {
            let _g = Guard { cond: self.cond };
            debug!("Trap: pushing handler to TLS");
            task::local_data::local_data_set(self.cond.key, self.handler);
            inner()
        }
    }
}

struct Guard<T, U:Copy> {
    cond: &Condition<T,U>,
    drop {
        unsafe {
            debug!("Guard: popping handler from TLS");
            let curr = task::local_data::local_data_pop(self.cond.key);
            match curr {
                None => (),
                Some(h) =>
                match h.prev {
                    None => (),
                    Some(hp) => {
                        task::local_data::local_data_set(self.cond.key, hp)
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod test {

    fn sadness_key(_x: @Handler<int,int>) { }
    fn trouble(i: int) {
        // Condition should work as a const, just limitations in consts.
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };
        debug!("trouble: raising conition");
        let j = sadness_condition.raise(&i);
        debug!("trouble: handler recovered with %d", j);
    }

    fn nested_trap_test_inner() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut inner_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_trap_test_inner: in handler");
            inner_trapped = true;
            0
        }).in {
            debug!("nested_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_trap_test_outer() {

        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut outer_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_guard_test_outer: in protected block");
            nested_trap_test_inner();
            trouble(1);
        }

        assert outer_trapped;
    }

    fn nested_reraise_trap_test_inner() {
        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut inner_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_reraise_trap_test_inner: in handler");
            inner_trapped = true;
            let i = 10;
            debug!("nested_reraise_trap_test_inner: handler re-raising");
            sadness_condition.raise(&i)
        }).in {
            debug!("nested_reraise_trap_test_inner: in protected block");
            trouble(1);
        }

        assert inner_trapped;
    }

    #[test]
    fn nested_reraise_trap_test_outer() {

        let sadness_condition : Condition<int,int> =
            Condition { key: sadness_key };

        let mut outer_trapped = false;

        do sadness_condition.trap(|_j| {
            debug!("nested_reraise_trap_test_outer: in handler");
            outer_trapped = true; 0
        }).in {
            debug!("nested_reraise_trap_test_outer: in protected block");
            nested_reraise_trap_test_inner();
        }

        assert outer_trapped;
    }

}<|endoftext|>


<commit_before>use std::sync::Arc;

use num_complex::Complex;
use num_traits::Zero;

use common::{FFTnum, verify_length, verify_length_divisible};

use ::{Length, IsInverse, FFT};

/// Implementation of Bluestein's Algorithm
///
/// This algorithm computes a FFT of any size by using converting it to a convolution, where a longer FFT of an "easy" length is used.
/// The primary use is for prime-sized FFTs of lengths where Rader's alorithm is slow.
/// When performing a FFT the inner FFT is run twice. These FFTs make up nearly all the processing time.
/// There are also simple O(n) processing steps before, in between and after the inner FFTs.
///
/// This implementation is based on the one in the [fourier library](https://github.com/calebzulawski/fourier) by Caleb Zulawski.
/// ~~~
/// // Computes a forward FFT of size 1201 (prime number), using Bluesteins's Algorithm
/// use rustfft::algorithm::Bluesteins;
/// use rustfft::{FFT, FFTplanner};
/// use rustfft::num_complex::Complex;
/// use rustfft::num_traits::Zero;
///
/// let mut input:  Vec<Complex<f32>> = vec![Zero::zero(); 1201];
/// let mut output: Vec<Complex<f32>> = vec![Zero::zero(); 1201];
///
/// // Plan a forward FFT for the nearest power of two larger or equal to 2 * 1201 - 1 -> 4096
/// // Note that the inner fft determines if the Bluestein fft is a forward or inverse transform.
/// let mut planner = FFTplanner::new(false);
/// let inner_fft = planner.plan_fft(4096);
///
/// let fft = Bluesteins::new(1201, inner_fft);
/// fft.process(&mut input, &mut output);
/// ~~~
///
/// Bluestein's algorithm is mainly useful for prime-length FFTs, and in particular for the lengths where
/// Rader's algorithm is slow due to hitting a Cunningham Chain.

pub struct Bluesteins<T> {
    len: usize,
    inner_fft: Arc<FFT<T>>,
    w_twiddles: Box<[Complex<T>]>,
    x_twiddles: Box<[Complex<T>]>,
}

fn calculate_twiddle<T: FFTnum>(index: f64, len: usize) -> Complex<T> {
    let theta = index * core::f64::consts::PI / len as f64;
    Complex::new(
        T::from_f64(theta.cos()).unwrap(),
        T::from_f64(-theta.sin()).unwrap(),
    )
}

/// Calculate the "w" twiddles.
fn calculate_w_twiddles<T: FFTnum>(
    len: usize,
    fft: &Arc<FFT<T>>,
    twiddles: &mut [Complex<T>],
) {
    let mut scratch = vec![Complex::zero(); fft.len()];
    let scale = T::one() / T::from_usize(fft.len()).unwrap();
    for (i, tw) in scratch.iter_mut().enumerate() {
        if let Some(index) = {
            if i < len {
                Some((i as f64).powi(2))
            } else if i > fft.len() - len {
                Some(((i as f64) - (fft.len() as f64)).powi(2))
            } else {
                None
            }
        } {
            *tw = calculate_twiddle(index, len).conj()*scale;
        }
    }
    fft.process(&mut scratch, &mut twiddles[..]);
    if fft.is_inverse() {
        for tw in twiddles.iter_mut() {
            *tw = tw.conj();
        }
    }
}

/// Calculate the "x" twiddles.
fn calculate_x_twiddles<T: FFTnum>(
    len: usize,
    twiddles: &mut [Complex<T>],
    inverse: bool,
) {
    if inverse {
        for (i, tw) in twiddles.iter_mut().enumerate() {
            *tw = calculate_twiddle(-(i as f64).powi(2), len);
        }
    }
    else {
        for (i, tw) in twiddles.iter_mut().enumerate() {
            *tw = calculate_twiddle(-(i as f64).powi(2), len).conj();
        }
    }
}

impl<T: FFTnum > Bluesteins<T> {
    /// Creates a FFT instance which will process inputs/outputs of size `len`. The inner FFT can be any length that is equal to or larger than `2 * len - 1`.
    /// The inner FFT determines if this becomes a forward or inverse transform.
    ///
    /// Note that this constructor is quite expensive to run; This algorithm must run a FFT within the
    /// constructor.
    pub fn new(len: usize, inner_fft: Arc<FFT<T>> ) -> Self {
        let min_inner_fft_len = 2 * len - 1;
        assert!(inner_fft.len() >= min_inner_fft_len, "For Bluesteins algorithm, inner_fft.len() must be equal to or larger than 2*self.len() - 1. Expected at least {}, got {}", min_inner_fft_len, inner_fft.len());

        let mut w_twiddles = vec![Complex::zero(); inner_fft.len()];
        let mut x_twiddles = vec![Complex::zero(); len];
        calculate_w_twiddles(len, &inner_fft, &mut w_twiddles);
        calculate_x_twiddles(len, &mut x_twiddles, inner_fft.is_inverse());
        Self {
            len,
            inner_fft,
            w_twiddles: w_twiddles.into_boxed_slice(),
            x_twiddles: x_twiddles.into_boxed_slice(),
        }
    }

    fn perform_fft(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        // The steps of this algorithm are:
        // - Multiply inputs with the X twiddles, and store in the first `len` elements of longer vector.
        // - Perform a forward FFT of this vector to get a "spectrum".
        // - Multipy the spectrum with the W twiddles.
        // - Inverse transform the modified spectrum.
        // - Multiply first `len` elements of the iFFT output with the X-twiddles, and store in the output.
        //
        // By using the fact that iFFT(X) = FFT(X*)* and FFT(X) = iFFT(X*)*, we can use a single inner
        // FFT for both forward and inverse transform, by conjugating the inputs and outputs as needed.

        assert_eq!(self.len(), input.len());

        let mut scratch = vec![Complex::zero(); 2*self.inner_fft.len()];
        let (mut scratch_a, mut scratch_b) = scratch.split_at_mut(self.inner_fft.len());
        // Copy input data to scratch vector, and multiply with X twiddles.
        // If the inner FFT is inverse, then we conjugate the input here to make the first FFT step a forward transform
        if self.inner_fft.is_inverse() {
            for (w, (x, i)) in scratch_a.iter_mut().zip(self.x_twiddles.iter().zip(input.iter())) {
                *w = (x * i).conj();
            }
        }
        else {
            for (w, (x, i)) in scratch_a.iter_mut().zip(self.x_twiddles.iter().zip(input.iter())) {
                *w = x * i;
            }
        }

        // Perform forward FFT (either directly or using an inverse FFT with conjugated inputs and outputs).
        self.inner_fft.process(&mut scratch_a, &mut scratch_b);

        // Multiply spectrum with W twiddles.
        // If the inner FFT is inverse, then we conjugate the results from the first FFT step to make it a forward transform.
        if self.inner_fft.is_inverse() {
            for (w, wi) in scratch_b.iter_mut().zip(self.w_twiddles.iter()) {
                *w = w.conj() * wi;
            }
        }
        // If the inner FFT is forward, then we conjugate the input to the second FFT step here to make it an inverse transform
        else {
            for (w, wi) in scratch_b.iter_mut().zip(self.w_twiddles.iter()) {
                *w = (*w * wi).conj();
            }
        }

        // Perform inverse FFT (either directly or using a forward FFT with conjugated inputs and outputs).
        self.inner_fft.process(&mut scratch_b, &mut scratch_a);

        // Multiply with X twiddles and store in output.
        // If the inner FFT is inverse, use the output directly.
        if self.inner_fft.is_inverse() {
            for (i, (w, xi)) in output.iter_mut().zip(scratch_a.iter().zip(self.x_twiddles.iter())) {
                *i = w * xi;
            }
        }
        // If the inner FFT is forward, then we conjugate the output from the second FFT step to make it an inverse transform.
        else {
            for (i, (w, xi)) in output.iter_mut().zip(scratch_a.iter().zip(self.x_twiddles.iter())) {
                *i = w.conj() * xi;
            }
        }
    }

}

impl<T: FFTnum> FFT<T> for Bluesteins<T> {
    fn process(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length(input, output, self.len());

        self.perform_fft(input, output);
    }
    fn process_multi(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length_divisible(input, output, self.len());

        for (in_chunk, out_chunk) in input.chunks_mut(self.len()).zip(output.chunks_mut(self.len())) {
            self.perform_fft(in_chunk, out_chunk);
        }
    }
}
impl<T> Length for Bluesteins<T> {
    #[inline(always)]
    fn len(&self) -> usize {
        self.len
    }
}
impl<T> IsInverse for Bluesteins<T> {
    #[inline(always)]
    fn is_inverse(&self) -> bool {
        self.inner_fft.is_inverse()
    }
}

#[cfg(test)]
mod unit_tests {
    use super::*;
    use std::sync::Arc;
    use test_utils::check_fft_algorithm;
    use algorithm::DFT;

    #[test]
    fn test_bluestein() {
        for &len in &[3,5,7,11,13,123] {
            test_bluestein_with_length(len, false);
            test_bluestein_with_length(len, true);
        }
    }

    fn test_bluestein_with_length(len: usize, inverse: bool) {
        let inner_fft_len = (2 * len - 1).checked_next_power_of_two().unwrap();
        let inner_fft = Arc::new(DFT::new(inner_fft_len, inverse));
        let fft = Bluesteins::new(len, inner_fft);

        check_fft_algorithm(&fft, len, inverse);
    }
}
<commit_msg>Updates bluesteins implementation to 2018<commit_after>use std::sync::Arc;

use num_complex::Complex;
use num_traits::Zero;

use crate::common::{FFTnum, verify_length, verify_length_divisible};

use crate::{Length, IsInverse, FFT};

/// Implementation of Bluestein's Algorithm
///
/// This algorithm computes a FFT of any size by using converting it to a convolution, where a longer FFT of an "easy" length is used.
/// The primary use is for prime-sized FFTs of lengths where Rader's alorithm is slow.
/// When performing a FFT the inner FFT is run twice. These FFTs make up nearly all the processing time.
/// There are also simple O(n) processing steps before, in between and after the inner FFTs.
///
/// This implementation is based on the one in the [fourier library](https://github.com/calebzulawski/fourier) by Caleb Zulawski.
/// ~~~
/// // Computes a forward FFT of size 1201 (prime number), using Bluesteins's Algorithm
/// use rustfft::algorithm::Bluesteins;
/// use rustfft::{FFT, FFTplanner};
/// use rustfft::num_complex::Complex;
/// use rustfft::num_traits::Zero;
///
/// let mut input:  Vec<Complex<f32>> = vec![Zero::zero(); 1201];
/// let mut output: Vec<Complex<f32>> = vec![Zero::zero(); 1201];
///
/// // Plan a forward FFT for the nearest power of two larger or equal to 2 * 1201 - 1 -> 4096
/// // Note that the inner fft determines if the Bluestein fft is a forward or inverse transform.
/// let mut planner = FFTplanner::new(false);
/// let inner_fft = planner.plan_fft(4096);
///
/// let fft = Bluesteins::new(1201, inner_fft);
/// fft.process(&mut input, &mut output);
/// ~~~
///
/// Bluestein's algorithm is mainly useful for prime-length FFTs, and in particular for the lengths where
/// Rader's algorithm is slow due to hitting a Cunningham Chain.

pub struct Bluesteins<T> {
    len: usize,
    inner_fft: Arc<FFT<T>>,
    w_twiddles: Box<[Complex<T>]>,
    x_twiddles: Box<[Complex<T>]>,
}

fn calculate_twiddle<T: FFTnum>(index: f64, len: usize) -> Complex<T> {
    let theta = index * core::f64::consts::PI / len as f64;
    Complex::new(
        T::from_f64(theta.cos()).unwrap(),
        T::from_f64(-theta.sin()).unwrap(),
    )
}

/// Calculate the "w" twiddles.
fn calculate_w_twiddles<T: FFTnum>(
    len: usize,
    fft: &Arc<FFT<T>>,
    twiddles: &mut [Complex<T>],
) {
    let mut scratch = vec![Complex::zero(); fft.len()];
    let scale = T::one() / T::from_usize(fft.len()).unwrap();
    for (i, tw) in scratch.iter_mut().enumerate() {
        if let Some(index) = {
            if i < len {
                Some((i as f64).powi(2))
            } else if i > fft.len() - len {
                Some(((i as f64) - (fft.len() as f64)).powi(2))
            } else {
                None
            }
        } {
            *tw = calculate_twiddle(index, len).conj()*scale;
        }
    }
    fft.process(&mut scratch, &mut twiddles[..]);
    if fft.is_inverse() {
        for tw in twiddles.iter_mut() {
            *tw = tw.conj();
        }
    }
}

/// Calculate the "x" twiddles.
fn calculate_x_twiddles<T: FFTnum>(
    len: usize,
    twiddles: &mut [Complex<T>],
    inverse: bool,
) {
    if inverse {
        for (i, tw) in twiddles.iter_mut().enumerate() {
            *tw = calculate_twiddle(-(i as f64).powi(2), len);
        }
    }
    else {
        for (i, tw) in twiddles.iter_mut().enumerate() {
            *tw = calculate_twiddle(-(i as f64).powi(2), len).conj();
        }
    }
}

impl<T: FFTnum > Bluesteins<T> {
    /// Creates a FFT instance which will process inputs/outputs of size `len`. The inner FFT can be any length that is equal to or larger than `2 * len - 1`.
    /// The inner FFT determines if this becomes a forward or inverse transform.
    ///
    /// Note that this constructor is quite expensive to run; This algorithm must run a FFT within the
    /// constructor.
    pub fn new(len: usize, inner_fft: Arc<FFT<T>> ) -> Self {
        let min_inner_fft_len = 2 * len - 1;
        assert!(inner_fft.len() >= min_inner_fft_len, "For Bluesteins algorithm, inner_fft.len() must be equal to or larger than 2*self.len() - 1. Expected at least {}, got {}", min_inner_fft_len, inner_fft.len());

        let mut w_twiddles = vec![Complex::zero(); inner_fft.len()];
        let mut x_twiddles = vec![Complex::zero(); len];
        calculate_w_twiddles(len, &inner_fft, &mut w_twiddles);
        calculate_x_twiddles(len, &mut x_twiddles, inner_fft.is_inverse());
        Self {
            len,
            inner_fft,
            w_twiddles: w_twiddles.into_boxed_slice(),
            x_twiddles: x_twiddles.into_boxed_slice(),
        }
    }

    fn perform_fft(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        // The steps of this algorithm are:
        // - Multiply inputs with the X twiddles, and store in the first `len` elements of longer vector.
        // - Perform a forward FFT of this vector to get a "spectrum".
        // - Multipy the spectrum with the W twiddles.
        // - Inverse transform the modified spectrum.
        // - Multiply first `len` elements of the iFFT output with the X-twiddles, and store in the output.
        //
        // By using the fact that iFFT(X) = FFT(X*)* and FFT(X) = iFFT(X*)*, we can use a single inner
        // FFT for both forward and inverse transform, by conjugating the inputs and outputs as needed.

        assert_eq!(self.len(), input.len());

        let mut scratch = vec![Complex::zero(); 2*self.inner_fft.len()];
        let (mut scratch_a, mut scratch_b) = scratch.split_at_mut(self.inner_fft.len());
        // Copy input data to scratch vector, and multiply with X twiddles.
        // If the inner FFT is inverse, then we conjugate the input here to make the first FFT step a forward transform
        if self.inner_fft.is_inverse() {
            for (w, (x, i)) in scratch_a.iter_mut().zip(self.x_twiddles.iter().zip(input.iter())) {
                *w = (x * i).conj();
            }
        }
        else {
            for (w, (x, i)) in scratch_a.iter_mut().zip(self.x_twiddles.iter().zip(input.iter())) {
                *w = x * i;
            }
        }

        // Perform forward FFT (either directly or using an inverse FFT with conjugated inputs and outputs).
        self.inner_fft.process(&mut scratch_a, &mut scratch_b);

        // Multiply spectrum with W twiddles.
        // If the inner FFT is inverse, then we conjugate the results from the first FFT step to make it a forward transform.
        if self.inner_fft.is_inverse() {
            for (w, wi) in scratch_b.iter_mut().zip(self.w_twiddles.iter()) {
                *w = w.conj() * wi;
            }
        }
        // If the inner FFT is forward, then we conjugate the input to the second FFT step here to make it an inverse transform
        else {
            for (w, wi) in scratch_b.iter_mut().zip(self.w_twiddles.iter()) {
                *w = (*w * wi).conj();
            }
        }

        // Perform inverse FFT (either directly or using a forward FFT with conjugated inputs and outputs).
        self.inner_fft.process(&mut scratch_b, &mut scratch_a);

        // Multiply with X twiddles and store in output.
        // If the inner FFT is inverse, use the output directly.
        if self.inner_fft.is_inverse() {
            for (i, (w, xi)) in output.iter_mut().zip(scratch_a.iter().zip(self.x_twiddles.iter())) {
                *i = w * xi;
            }
        }
        // If the inner FFT is forward, then we conjugate the output from the second FFT step to make it an inverse transform.
        else {
            for (i, (w, xi)) in output.iter_mut().zip(scratch_a.iter().zip(self.x_twiddles.iter())) {
                *i = w.conj() * xi;
            }
        }
    }

}

impl<T: FFTnum> FFT<T> for Bluesteins<T> {
    fn process(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length(input, output, self.len());

        self.perform_fft(input, output);
    }
    fn process_multi(&self, input: &mut [Complex<T>], output: &mut [Complex<T>]) {
        verify_length_divisible(input, output, self.len());

        for (in_chunk, out_chunk) in input.chunks_mut(self.len()).zip(output.chunks_mut(self.len())) {
            self.perform_fft(in_chunk, out_chunk);
        }
    }
}
impl<T> Length for Bluesteins<T> {
    #[inline(always)]
    fn len(&self) -> usize {
        self.len
    }
}
impl<T> IsInverse for Bluesteins<T> {
    #[inline(always)]
    fn is_inverse(&self) -> bool {
        self.inner_fft.is_inverse()
    }
}

#[cfg(test)]
mod unit_tests {
    use super::*;
    use std::sync::Arc;
    use crate::test_utils::check_fft_algorithm;
    use crate::algorithm::DFT;

    #[test]
    fn test_bluestein() {
        for &len in &[3,5,7,11,13,123] {
            test_bluestein_with_length(len, false);
            test_bluestein_with_length(len, true);
        }
    }

    fn test_bluestein_with_length(len: usize, inverse: bool) {
        let inner_fft_len = (2 * len - 1).checked_next_power_of_two().unwrap();
        let inner_fft = Arc::new(DFT::new(inner_fft_len, inverse));
        let fft = Bluesteins::new(len, inner_fft);

        check_fft_algorithm(&fft, len, inverse);
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;

use std::comm::{Receiver, Sender};
use std::char;
use std::io::{fs, File, FileMode, FileAccess, TempDir};
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};

use super::Response;
use input::Input;
use cursor::Direction;
use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use view::View;

#[deriving(Copy, Show)]
#[allow(dead_code)]
pub enum Command {
    SaveBuffer,
    ExitEditor,
    ResizeView,

    MoveCursor(Direction),
    LineEnd,
    LineStart,

    Delete(Direction),
    InsertTab,
    InsertLine,
    InsertChar(char)
}

enum EventStatus {
    Handled(Response),
    NotHandled,
}

pub struct Editor<'e> {
    pub running: Arc<AtomicBool>,
    pub sender: Sender<rustbox::Event>,

    keymap: KeyMap,
    events: Receiver<rustbox::Event>,
    view: View<'e>,
}

impl<'e> Editor<'e> {
    pub fn new(source: Input) -> Editor<'e> {
        let view = View::new(source);
        let (send, recv) = channel();
        let keymap = KeyMap::load_defaults();

        Editor {
            sender: send,
            events: recv,
            view: view,
            running: Arc::new(AtomicBool::new(false)),
            keymap: keymap,
        }
    }

    pub fn handle_key_event(&mut self, key: u16, ch: u32) -> Response {
        let key = match key {
            0 => char::from_u32(ch).map(|c| Key::Char(c)),
            a => Key::from_special_code(a),
        };

        match self.handle_system_event(key) {
            EventStatus::Handled(response) => { response }
            EventStatus::NotHandled        => { Response::Continue }
        }
    }

    pub fn save_active_buffer(&mut self) {
        let lines = &self.view.buffer.lines;
        let path = match self.view.buffer.file_path {
            Some(ref p) => p.clone(),
            None => {
                // TODO: prompt user for file name here
                Path::new("untitled")
            },
        };

        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));

        let mut file = match File::open_mode(&tmppath, FileMode::Open, FileAccess::Write) {
            Ok(f) => f,
            Err(e) => panic!("file error: {}", e)
        };

        for line in lines.iter() {
            let mut data = line.data.clone();
            data.push('\n');
            let result = file.write(data.as_bytes());

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = fs::rename(&tmppath, &path) {
            panic!("file error: {}", e);
        }
    }

    pub fn draw(&mut self) {
        self.view.draw();
        self.view.draw_status();
        self.view.draw_cursor();
    }

    pub fn start(&mut self) {
        // Synchronizes with transfer across thread boundary
        self.running.store(true, Ordering::Relaxed);
        self.event_loop();
        self.main_loop();
    }

    fn main_loop(&mut self) {
        while self.running.load(Ordering::Relaxed) {
            self.view.clear();
            self.draw();
            rustbox::present();
            if let rustbox::Event::KeyEvent(_, key, ch) = self.events.recv() {
                if let Response::Quit = self.handle_key_event(key, ch) {
                    // Okay if it doesn't quit immediately.
                    self.running.store(false, Ordering::Relaxed);
                }
            }
        }
    }

    fn event_loop(&self) {
        // clone the sender so that we can use it in the proc
        let sender = self.sender.clone();
        let running = self.running.clone();

        spawn(move || {
            while running.load(Ordering::Relaxed) {
                if sender.send_opt(rustbox::peek_event(1000)).is_err() {
                    running.store(false, Ordering::Relaxed);
                }
            }
        });
    }

    fn handle_command(&mut self, c: Command) {
        match c {
            // Editor Commands
            Command::ExitEditor      => self.running.store(false, Ordering::Relaxed),
            Command::SaveBuffer      => self.save_active_buffer(),
            Command::ResizeView      => self.view.resize(),

            // Navigation
            Command::MoveCursor(dir) => self.view.move_cursor(dir),
            Command::LineEnd         => self.view.move_cursor_to_line_end(),
            Command::LineStart       => self.view.move_cursor_to_line_start(),

            // Editing
            Command::Delete(dir)     => self.view.delete_char(dir),
            Command::InsertTab       => self.view.insert_tab(),
            Command::InsertLine      => self.view.insert_line(),
            Command::InsertChar(c)   => self.view.insert_char(c)
        }
    }

    fn handle_system_event(&mut self, k: Option<Key>) -> EventStatus {
        let key = match k {
            Some(k) => k,
            None => return EventStatus::NotHandled
        };

        // send key to the keymap
        match self.keymap.check_key(key) {
            KeyMapState::Match(command) => {
                self.handle_command(command);
                return EventStatus::Handled(Response::Continue)
            },
            KeyMapState::Continue => {
                // keep going and wait for more keypresses
                return EventStatus::Handled(Response::Continue)
            },
            KeyMapState::None => {}  // do nothing and handle the key normally
        }

        // if the key is a character that is not part of a keybinding, insert into the buffer
        // otherwise, ignore it.
        if let Key::Char(c) = key {
            self.view.insert_char(c);
            EventStatus::Handled(Response::Continue)
        } else {
            EventStatus::NotHandled
        }
    }
}
<commit_msg>Use Cow instead of clone<commit_after>extern crate rustbox;

use std::comm::{Receiver, Sender};
use std::char;
use std::io::{fs, File, FileMode, FileAccess, TempDir};
use std::sync::Arc;
use std::sync::atomic::{Ordering, AtomicBool};
use std::borrow::Cow;

use super::Response;
use input::Input;
use cursor::Direction;
use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use view::View;

#[deriving(Copy, Show)]
#[allow(dead_code)]
pub enum Command {
    SaveBuffer,
    ExitEditor,
    ResizeView,

    MoveCursor(Direction),
    LineEnd,
    LineStart,

    Delete(Direction),
    InsertTab,
    InsertLine,
    InsertChar(char)
}

enum EventStatus {
    Handled(Response),
    NotHandled,
}

pub struct Editor<'e> {
    pub running: Arc<AtomicBool>,
    pub sender: Sender<rustbox::Event>,

    keymap: KeyMap,
    events: Receiver<rustbox::Event>,
    view: View<'e>,
}

impl<'e> Editor<'e> {
    pub fn new(source: Input) -> Editor<'e> {
        let view = View::new(source);
        let (send, recv) = channel();
        let keymap = KeyMap::load_defaults();

        Editor {
            sender: send,
            events: recv,
            view: view,
            running: Arc::new(AtomicBool::new(false)),
            keymap: keymap,
        }
    }

    pub fn handle_key_event(&mut self, key: u16, ch: u32) -> Response {
        let key = match key {
            0 => char::from_u32(ch).map(|c| Key::Char(c)),
            a => Key::from_special_code(a),
        };

        match self.handle_system_event(key) {
            EventStatus::Handled(response) => { response }
            EventStatus::NotHandled        => { Response::Continue }
        }
    }

    pub fn save_active_buffer(&mut self) {
        let lines = &self.view.buffer.lines;
        let path = match self.view.buffer.file_path {
            Some(ref p) => Cow::Borrowed(p),
            None => {
                // TODO: prompt user for file name here
                Cow::Owned(Path::new("untitled"))
            },
        };

        let tmpdir = match TempDir::new_in(&Path::new("."), "iota") {
            Ok(d) => d,
            Err(e) => panic!("file error: {}", e)
        };

        let tmppath = tmpdir.path().join(Path::new("tmpfile"));

        let mut file = match File::open_mode(&tmppath, FileMode::Open, FileAccess::Write) {
            Ok(f) => f,
            Err(e) => panic!("file error: {}", e)
        };

        for line in lines.iter() {
            let mut data = line.data.clone();
            data.push('\n');
            let result = file.write(data.as_bytes());

            if result.is_err() {
                // TODO(greg): figure out what to do here.
                panic!("Something went wrong while writing the file");
            }
        }

        if let Err(e) = fs::rename(&tmppath, &*path) {
            panic!("file error: {}", e);
        }
    }

    pub fn draw(&mut self) {
        self.view.draw();
        self.view.draw_status();
        self.view.draw_cursor();
    }

    pub fn start(&mut self) {
        // Synchronizes with transfer across thread boundary
        self.running.store(true, Ordering::Relaxed);
        self.event_loop();
        self.main_loop();
    }

    fn main_loop(&mut self) {
        while self.running.load(Ordering::Relaxed) {
            self.view.clear();
            self.draw();
            rustbox::present();
            if let rustbox::Event::KeyEvent(_, key, ch) = self.events.recv() {
                if let Response::Quit = self.handle_key_event(key, ch) {
                    // Okay if it doesn't quit immediately.
                    self.running.store(false, Ordering::Relaxed);
                }
            }
        }
    }

    fn event_loop(&self) {
        // clone the sender so that we can use it in the proc
        let sender = self.sender.clone();
        let running = self.running.clone();

        spawn(move || {
            while running.load(Ordering::Relaxed) {
                if sender.send_opt(rustbox::peek_event(1000)).is_err() {
                    running.store(false, Ordering::Relaxed);
                }
            }
        });
    }

    fn handle_command(&mut self, c: Command) {
        match c {
            // Editor Commands
            Command::ExitEditor      => self.running.store(false, Ordering::Relaxed),
            Command::SaveBuffer      => self.save_active_buffer(),
            Command::ResizeView      => self.view.resize(),

            // Navigation
            Command::MoveCursor(dir) => self.view.move_cursor(dir),
            Command::LineEnd         => self.view.move_cursor_to_line_end(),
            Command::LineStart       => self.view.move_cursor_to_line_start(),

            // Editing
            Command::Delete(dir)     => self.view.delete_char(dir),
            Command::InsertTab       => self.view.insert_tab(),
            Command::InsertLine      => self.view.insert_line(),
            Command::InsertChar(c)   => self.view.insert_char(c)
        }
    }

    fn handle_system_event(&mut self, k: Option<Key>) -> EventStatus {
        let key = match k {
            Some(k) => k,
            None => return EventStatus::NotHandled
        };

        // send key to the keymap
        match self.keymap.check_key(key) {
            KeyMapState::Match(command) => {
                self.handle_command(command);
                return EventStatus::Handled(Response::Continue)
            },
            KeyMapState::Continue => {
                // keep going and wait for more keypresses
                return EventStatus::Handled(Response::Continue)
            },
            KeyMapState::None => {}  // do nothing and handle the key normally
        }

        // if the key is a character that is not part of a keybinding, insert into the buffer
        // otherwise, ignore it.
        if let Key::Char(c) = key {
            self.view.insert_char(c);
            EventStatus::Handled(Response::Continue)
        } else {
            EventStatus::NotHandled
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::OsString;
use std::iter;
use std::path::Path;

use crate::core::{TargetKind, Workspace};
use crate::ops;
use crate::util::CargoResult;

pub fn run(
    ws: &Workspace<'_>,
    options: &ops::CompileOptions,
    args: &[OsString],
) -> CargoResult<()> {
    let config = ws.config();

    if options.filter.contains_glob_patterns() {
        anyhow::bail!("`cargo run` does not support glob patterns on target selection")
    }

    // We compute the `bins` here *just for diagnosis*. The actual set of
    // packages to be run is determined by the `ops::compile` call below.
    let packages = options.spec.get_packages(ws)?;
    let bins: Vec<_> = packages
        .into_iter()
        .flat_map(|pkg| {
            iter::repeat(pkg).zip(pkg.manifest().targets().iter().filter(|target| {
                !target.is_lib()
                    && !target.is_custom_build()
                    && if !options.filter.is_specific() {
                        target.is_bin()
                    } else {
                        options.filter.target_run(target)
                    }
            }))
        })
        .collect();

    if bins.is_empty() {
        if !options.filter.is_specific() {
            anyhow::bail!("a bin target must be available for `cargo run`")
        } else {
            // This will be verified in `cargo_compile`.
        }
    }

    if bins.len() == 1 {
        let target = bins[0].1;
        if let TargetKind::ExampleLib(..) = target.kind() {
            anyhow::bail!(
                "example target `{}` is a library and cannot be executed",
                target.name()
            )
        }
    }

    if bins.len() > 1 {
        if !options.filter.is_specific() {
            let names: Vec<&str> = bins
                .into_iter()
                .map(|(_pkg, target)| target.name())
                .collect();
            anyhow::bail!(
                "`cargo run` could not determine which binary to run. \
                 Use the `--bin` option to specify a binary, \
                 or the `default-run` manifest key.\n\
                 available binaries: {}",
                names.join(", ")
            )
        } else {
            anyhow::bail!(
                "`cargo run` can run at most one executable, but \
                 multiple were specified"
            )
        }
    }

    // `cargo run` is only compatible with one `--target` flag at most
    options.build_config.single_requested_kind()?;

    let compile = ops::compile(ws, options)?;
    assert_eq!(compile.binaries.len(), 1);
    let (unit, exe) = &compile.binaries[0];
    let exe = match exe.strip_prefix(config.cwd()) {
        Ok(path) if path.file_name() == Some(path.as_os_str()) => Path::new(".").join(path),
        Ok(path) => path.to_path_buf(),
        Err(_) => exe.to_path_buf(),
    };
    let pkg = bins[0].0;
    let mut process = compile.target_process(exe, unit.kind, pkg)?;
    process.args(args).cwd(config.cwd());

    config.shell().status("Running", process.to_string())?;

    process.exec_replace()
}
<commit_msg>Sort available binaries when multiple<commit_after>use std::ffi::OsString;
use std::iter;
use std::path::Path;

use crate::core::{TargetKind, Workspace};
use crate::ops;
use crate::util::CargoResult;

pub fn run(
    ws: &Workspace<'_>,
    options: &ops::CompileOptions,
    args: &[OsString],
) -> CargoResult<()> {
    let config = ws.config();

    if options.filter.contains_glob_patterns() {
        anyhow::bail!("`cargo run` does not support glob patterns on target selection")
    }

    // We compute the `bins` here *just for diagnosis*. The actual set of
    // packages to be run is determined by the `ops::compile` call below.
    let packages = options.spec.get_packages(ws)?;
    let bins: Vec<_> = packages
        .into_iter()
        .flat_map(|pkg| {
            iter::repeat(pkg).zip(pkg.manifest().targets().iter().filter(|target| {
                !target.is_lib()
                    && !target.is_custom_build()
                    && if !options.filter.is_specific() {
                        target.is_bin()
                    } else {
                        options.filter.target_run(target)
                    }
            }))
        })
        .collect();

    if bins.is_empty() {
        if !options.filter.is_specific() {
            anyhow::bail!("a bin target must be available for `cargo run`")
        } else {
            // This will be verified in `cargo_compile`.
        }
    }

    if bins.len() == 1 {
        let target = bins[0].1;
        if let TargetKind::ExampleLib(..) = target.kind() {
            anyhow::bail!(
                "example target `{}` is a library and cannot be executed",
                target.name()
            )
        }
    }

    if bins.len() > 1 {
        if !options.filter.is_specific() {
            let mut names: Vec<&str> = bins
                .into_iter()
                .map(|(_pkg, target)| target.name())
                .collect();
            names.sort();
            anyhow::bail!(
                "`cargo run` could not determine which binary to run. \
                 Use the `--bin` option to specify a binary, \
                 or the `default-run` manifest key.\n\
                 available binaries: {}",
                names.join(", ")
            )
        } else {
            anyhow::bail!(
                "`cargo run` can run at most one executable, but \
                 multiple were specified"
            )
        }
    }

    // `cargo run` is only compatible with one `--target` flag at most
    options.build_config.single_requested_kind()?;

    let compile = ops::compile(ws, options)?;
    assert_eq!(compile.binaries.len(), 1);
    let (unit, exe) = &compile.binaries[0];
    let exe = match exe.strip_prefix(config.cwd()) {
        Ok(path) if path.file_name() == Some(path.as_os_str()) => Path::new(".").join(path),
        Ok(path) => path.to_path_buf(),
        Err(_) => exe.to_path_buf(),
    };
    let pkg = bins[0].0;
    let mut process = compile.target_process(exe, unit.kind, pkg)?;
    process.args(args).cwd(config.cwd());

    config.shell().status("Running", process.to_string())?;

    process.exec_replace()
}
<|endoftext|>


<commit_before>//! Implements a command for sending events to Sentry.
use clap::{App, Arg, ArgMatches};
use itertools::Itertools;

use prelude::*;
use config::Config;
use event::Event;
use api::Api;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("sends an event to Sentry")
        .arg(Arg::with_name("level")
            .value_name("LEVEL")
            .long("level")
            .short("l")
            .help("Set the log level. Defaults to error"))
        .arg(Arg::with_name("release")
            .value_name("RELEASE")
            .long("release")
            .short("r")
            .help("Set the release."))
        .arg(Arg::with_name("dist")
            .value_name("DISTRIBUTION")
            .long("dist")
            .short("d")
            .help("Set the distribution."))
        .arg(Arg::with_name("environment")
            .value_name("ENVIRONMENT")
            .long("env")
            .short("E")
            .help("Send with a specific environment."))
        .arg(Arg::with_name("message")
            .value_name("MESSAGE")
            .long("message")
            .short("m")
            .multiple(true)
            .number_of_values(1)
            .help("Set the message to log"))
        .arg(Arg::with_name("platform")
            .value_name("PLATFORM")
            .long("platform")
            .short("p")
            .help("Overrides the default 'other' platform"))
        .arg(Arg::with_name("tags")
            .value_name("KEY:VALUE")
            .long("tag")
            .short("t")
            .multiple(true)
            .number_of_values(1)
            .help("Adds a tag (key:value) to the event."))
        .arg(Arg::with_name("extra")
            .value_name("KEY:VALUE")
            .long("extra")
            .short("e")
            .multiple(true)
            .number_of_values(1)
            .help("Adds extra information (key:value) to the event."))
        .arg(Arg::with_name("user_data")
             .value_name("KEY:VALUE")
             .long("user")
             .short("u")
            .multiple(true)
            .number_of_values(1)
            .help("Adds user information (key:value) to the event. \
                   eg: id:42, username:foo"))
        .arg(Arg::with_name("fingerprint")
            .value_name("FINGERPRINT")
            .long("fingerprint")
            .short("f")
            .multiple(true)
            .number_of_values(1)
            .help("Changes the fingerprint of the event"))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    let mut event = Event::new();
    event.level = matches.value_of("level").unwrap_or("error").into();
    event.release = matches.value_of("release").map(|x| x.into());
    event.dist = matches.value_of("dist").map(|x| x.into());
    event.platform = matches.value_of("platform").unwrap_or("other").into();
    event.message = matches.values_of("message").map(|mut x| x.join("\n"));
    event.environment = matches.value_of("environment").map(|x| x.into());

    if let Some(tags) = matches.values_of("tags") {
        for tag in tags {
            let mut split = tag.splitn(2, ':');
            let key = split.next().ok_or("missing tag key")?;
            let value = split.next().ok_or("missing tag value")?;
            event.tags.insert(key.into(), value.into());
        }
    }

    if let Some(extra) = matches.values_of("tags") {
        for pair in extra {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing extra key")?;
            let value = split.next().ok_or("missing extra value")?;
            event.extra.insert(key.into(), value.into());
        }
    }

    if let Some(user_data) = matches.values_of("user_data") {
        for pair in user_data {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing user key")?;
            let value = split.next().ok_or("missing user value")?;
            event.user.insert(key.into(), value.into());
        }
    }

    if let Some(fingerprint) = matches.values_of("fingerprint") {
        event.fingerprint = Some(fingerprint.map(|x| x.to_string()).collect());
    }

    let dsn = config.get_dsn()?;

    // handle errors here locally so that we do not get the extra "use sentry-cli
    // login" to sign in which would be in appropriate here.
    match Api::new(config).send_event(&dsn, &event) {
        Ok(event_id) => {
            println!("Event sent: {}", event_id);
        }
        Err(err) => {
            println!("error: could not send event: {}", err);
        }
    };

    Ok(())
}
<commit_msg>fix(event): Fix typo leading to --extra param being ignored (#133)<commit_after>//! Implements a command for sending events to Sentry.
use clap::{App, Arg, ArgMatches};
use itertools::Itertools;

use prelude::*;
use config::Config;
use event::Event;
use api::Api;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("sends an event to Sentry")
        .arg(Arg::with_name("level")
            .value_name("LEVEL")
            .long("level")
            .short("l")
            .help("Set the log level. Defaults to error"))
        .arg(Arg::with_name("release")
            .value_name("RELEASE")
            .long("release")
            .short("r")
            .help("Set the release."))
        .arg(Arg::with_name("dist")
            .value_name("DISTRIBUTION")
            .long("dist")
            .short("d")
            .help("Set the distribution."))
        .arg(Arg::with_name("environment")
            .value_name("ENVIRONMENT")
            .long("env")
            .short("E")
            .help("Send with a specific environment."))
        .arg(Arg::with_name("message")
            .value_name("MESSAGE")
            .long("message")
            .short("m")
            .multiple(true)
            .number_of_values(1)
            .help("Set the message to log"))
        .arg(Arg::with_name("platform")
            .value_name("PLATFORM")
            .long("platform")
            .short("p")
            .help("Overrides the default 'other' platform"))
        .arg(Arg::with_name("tags")
            .value_name("KEY:VALUE")
            .long("tag")
            .short("t")
            .multiple(true)
            .number_of_values(1)
            .help("Adds a tag (key:value) to the event."))
        .arg(Arg::with_name("extra")
            .value_name("KEY:VALUE")
            .long("extra")
            .short("e")
            .multiple(true)
            .number_of_values(1)
            .help("Adds extra information (key:value) to the event."))
        .arg(Arg::with_name("user_data")
             .value_name("KEY:VALUE")
             .long("user")
             .short("u")
            .multiple(true)
            .number_of_values(1)
            .help("Adds user information (key:value) to the event. \
                   eg: id:42, username:foo"))
        .arg(Arg::with_name("fingerprint")
            .value_name("FINGERPRINT")
            .long("fingerprint")
            .short("f")
            .multiple(true)
            .number_of_values(1)
            .help("Changes the fingerprint of the event"))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    let mut event = Event::new();
    event.level = matches.value_of("level").unwrap_or("error").into();
    event.release = matches.value_of("release").map(|x| x.into());
    event.dist = matches.value_of("dist").map(|x| x.into());
    event.platform = matches.value_of("platform").unwrap_or("other").into();
    event.message = matches.values_of("message").map(|mut x| x.join("\n"));
    event.environment = matches.value_of("environment").map(|x| x.into());

    if let Some(tags) = matches.values_of("tags") {
        for tag in tags {
            let mut split = tag.splitn(2, ':');
            let key = split.next().ok_or("missing tag key")?;
            let value = split.next().ok_or("missing tag value")?;
            event.tags.insert(key.into(), value.into());
        }
    }

    if let Some(extra) = matches.values_of("extra") {
        for pair in extra {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing extra key")?;
            let value = split.next().ok_or("missing extra value")?;
            event.extra.insert(key.into(), value.into());
        }
    }

    if let Some(user_data) = matches.values_of("user_data") {
        for pair in user_data {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing user key")?;
            let value = split.next().ok_or("missing user value")?;
            event.user.insert(key.into(), value.into());
        }
    }

    if let Some(fingerprint) = matches.values_of("fingerprint") {
        event.fingerprint = Some(fingerprint.map(|x| x.to_string()).collect());
    }

    let dsn = config.get_dsn()?;

    // handle errors here locally so that we do not get the extra "use sentry-cli
    // login" to sign in which would be in appropriate here.
    match Api::new(config).send_event(&dsn, &event) {
        Ok(event_id) => {
            println!("Event sent: {}", event_id);
        }
        Err(err) => {
            println!("error: could not send event: {}", err);
        }
    };

    Ok(())
}
<|endoftext|>