<commit_before>use std::sync::{Mutex, Arc};
use std::net::{SocketAddr, ToSocketAddrs};
use std::f64::consts::PI;
use std::collections::VecDeque;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{Button, Key, MouseButton, RenderArgs, UpdateArgs};

use std::{thread, time};
use std::net::TcpStream;
use network::{Command, Message};

use bincode::{serialize_into, deserialize_from, Infinite};

use state::WorldState;
use shapes::Unit;
use colors::{BLACK, YELLOW, ORANGE};

pub mod menu;

use self::menu::Menu;

pub struct NetworkClient {
    pub world_state: Arc<Mutex<WorldState>>,
    server_addr: SocketAddr,
    stream: Option<TcpStream>,
    commands: Arc<Mutex<VecDeque<Command>>>,
}

impl NetworkClient {
    pub fn new<T: ToSocketAddrs>(server_addrs: T, world_state:
                                 Arc<Mutex<WorldState>>,
                                 commands: Arc<Mutex<VecDeque<Command>>>) -> NetworkClient {
        let server_addr = server_addrs.to_socket_addrs().unwrap().next().unwrap();
        NetworkClient {
            world_state: world_state,
            server_addr: server_addr,
            stream: None,
            commands: commands,
        }
    }

    // todo: Maybe return client_id here? Would allow the application to reconnect...
    pub fn connect(&mut self) {
        let mut stream = TcpStream::connect(self.server_addr).unwrap();
        serialize_into(&mut stream, &Message::ClientHello, Infinite).unwrap();
        let server_hello = deserialize_from(&mut stream, Infinite);

        self.stream = Some(stream);
        if let Ok(Message::ServerHello(_, world_state)) = server_hello {
            let mut world_state_lock = self.world_state.lock().unwrap();
            *world_state_lock = world_state;
        } else {
            panic!("Could not connect to server");
        }
    }

    pub fn update(self) {
        let stream = self.stream.expect("Stream not here :(");
        let mut command_stream = stream.try_clone().unwrap();
        let commands = self.commands.clone();

        // Command sender loop
        thread::spawn(move || {
            loop {
                let command = {
                    let mut commands = commands.lock().unwrap();
                    commands.pop_front()
                };
                command.map(|cmd| {
                    println!("Got command: {:?}", cmd);
                    //let cmd = Message::Command(Command::Move(0.into(), [100f64, 100f64]));
                    serialize_into(&mut command_stream, &Message::Command(cmd), Infinite)
                        .unwrap_or_else(|e|println!("Sending command failed: {}", e));
                });
                thread::sleep(time::Duration::from_millis(10));
            }
        });

        let mut game_state_stream = stream.try_clone().unwrap();
        let world_state = self.world_state.clone();
        thread::spawn(move || {
            loop {
                let game_state = deserialize_from(&mut game_state_stream,
                                                  Infinite);
                match game_state {
                    Ok(game) => {
                        //println!("{:?}", game);
                        let mut world_state_lock = world_state.lock().unwrap();
                        world_state_lock.game = game;

                    }
                    Err(e) => {
                        println!("{:?}", e);
                        thread::sleep(time::Duration::from_millis(200));
                    }
                }
            }
        });
    }
}

#[derive(Clone, Copy, Debug)]
pub enum State {
    Menu,
    Running,
}

pub struct App {
    pub gl: GlGraphics, // OpenGL drawing backend.
    pub world_state: Arc<Mutex<WorldState>>,
    pub units: Vec<Unit>,
    pub commands: Arc<Mutex<VecDeque<Command>>>,
    pub cursor: [f64; 2],
    pub state: State,
    menu: Menu,
}

impl App {
    pub fn new(gl: GlGraphics) -> App {
        App {
            gl: gl,
            world_state: Arc::new(Mutex::new(WorldState::new(0, 0))),
            units: vec![],
            commands: Arc::new(Mutex::new(VecDeque::new())),
            cursor: [0.0, 0.0],
            state: State::Menu,
            menu: Menu::new()
        }
    }

    pub fn start(&mut self) {
        let mut network_client = NetworkClient::new(("127.0.0.1", 8080), self.world_state.clone(), self.commands.clone());
        network_client.connect();
        network_client.update();
    }

    pub fn select(&mut self, position: [f64;2]) {
        for u in &mut self.units {
            u.selected = u.is_hit(position);
        };
    }

    fn render_game(&mut self, args: &RenderArgs, _: &mut GlyphCache) {
        use graphics::{polygon, clear};
        use graphics::Transformed;
        use graphics::types::Polygon;

        const FRONT_THICKNESS: f64 = 5.0;

        let units = &self.units;

        self.gl.draw(args.viewport(), |c, gl| {

            // Clear the screen.
            clear(BLACK, gl);

            for s in units.iter() {

                // Create a triangle polygon. The initial orientation is facing east.
                let triangle: Polygon = &s.get_shape();

                // Create a border on the front of the polygon. This is a trapezoid.
                // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                let front: Polygon = &[
                    [s.size, s.size],                                           // Top right
                    [s.size, 0.0],                                                 // Bottom right
                    [s.size - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                    [s.size - FRONT_THICKNESS, s.size - FRONT_THICKNESS / 2.0], // Top left
                ];

                // Rotate the front to match the unit
                let transform_front = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // We don't need to apply any transformation to the units
                let transform_triangle = c.transform;

                // Draw the unit ORANGE if selected
                if s.selected {
                    polygon(ORANGE, triangle, transform_triangle, gl);
                    polygon(YELLOW, front, transform_front, gl);
                } else {
                    polygon(YELLOW, triangle, transform_triangle, gl);
                    polygon(ORANGE, front, transform_front, gl);
                }

            }
        });
    }

    pub fn render(&mut self, args: &RenderArgs, cache: &mut GlyphCache) {
        match self.state {
            State::Menu => self.menu.render(args, &mut self.gl, cache), //self.render_menu(args, cache),
            State::Running => self.render_game(args, cache),
        }
    }

    pub fn update(&mut self, _: &UpdateArgs) {
        let player = {
            let world_lock = self.world_state.lock().unwrap();
            world_lock.game.players.get(0).map(|v| v.clone())
        };
        if let Some(player) = player {
            for unit in player.units.iter() {
                self.units.get_mut(unit.id.0 as usize)
                    .map(|app_unit| {
                        app_unit.position = unit.position;
                        app_unit.rotation = unit.angle;
                    })
                    .or_else(|| {
                        self.units.push(Unit::new(unit.position.clone(), unit.angle));
                        None
                    });
            }
        }
    }

    pub fn on_button_press(&mut self, button: &Button) {
        match self.state {
            State::Menu => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.menu.previous();
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.menu.next();
                    }
                    &Button::Keyboard(Key::Return) => {
                        match self.menu.get_selected_entry() {
                            menu::Entries::Start => {
                                self.start();
                                self.state = State::Running;
                            }
                            menu::Entries::Exit => {
                            }
                        }
                    }
                    _ => { }
                }
            }
            State::Running => {
                match button {
                    &Button::Keyboard(_) => { }
                    &Button::Mouse(button) => {
                        self.on_mouse_click(&button);
                    }
                    &Button::Controller(_) => { }
                }
            }
        };
    }

    pub fn on_mouse_click(&mut self, button: &MouseButton) {
        let cursor = self.cursor;
        match *button {
            MouseButton::Left  => self.select(cursor),
            MouseButton::Right => self.move_selected(cursor),
            _ => println!("Pressed mouse button '{:?}'", button),
        }
    }

    pub fn on_mouse_move(&mut self, cursor: [f64; 2]) {
        self.cursor = cursor;
    }

    pub fn move_selected(&mut self, position: [f64;2]) {
        for i in 0..self.units.len() {
            let s = &mut self.units[i];
            if s.selected {
                s.target = position;
                let dx = position[0] - s.position[0];
                let dy = position[1] - s.position[1];
                if dx.is_sign_negative() {
                    s.rotation = (dy / dx).atan() + PI;
                } else {
                    s.rotation = (dy / dx).atan();
                }
                let id = i as u32;
                let mut commands = self.commands.lock().unwrap();
                commands.push_back(Command::Move(id.into(), position));
                println!("dx: {}, dy: {}, new rotation: {}", dx, dy, s.rotation);
            }
        }
    }
}
<commit_msg>client: Remove unnecessary move in update()<commit_after>use std::sync::{Mutex, Arc};
use std::net::{SocketAddr, ToSocketAddrs};
use std::f64::consts::PI;
use std::collections::VecDeque;
use opengl_graphics::GlGraphics;
use opengl_graphics::glyph_cache::GlyphCache;
use piston::input::{Button, Key, MouseButton, RenderArgs, UpdateArgs};

use std::{thread, time};
use std::net::TcpStream;
use network::{Command, Message};

use bincode::{serialize_into, deserialize_from, Infinite};

use state::WorldState;
use shapes::Unit;
use colors::{BLACK, YELLOW, ORANGE};

pub mod menu;

use self::menu::Menu;

pub struct NetworkClient {
    pub world_state: Arc<Mutex<WorldState>>,
    server_addr: SocketAddr,
    stream: Option<TcpStream>,
    commands: Arc<Mutex<VecDeque<Command>>>,
}

impl NetworkClient {
    pub fn new<T: ToSocketAddrs>(server_addrs: T, world_state:
                                 Arc<Mutex<WorldState>>,
                                 commands: Arc<Mutex<VecDeque<Command>>>) -> NetworkClient {
        let server_addr = server_addrs.to_socket_addrs().unwrap().next().unwrap();
        NetworkClient {
            world_state: world_state,
            server_addr: server_addr,
            stream: None,
            commands: commands,
        }
    }

    // todo: Maybe return client_id here? Would allow the application to reconnect...
    pub fn connect(&mut self) {
        let mut stream = TcpStream::connect(self.server_addr).unwrap();
        serialize_into(&mut stream, &Message::ClientHello, Infinite).unwrap();
        let server_hello = deserialize_from(&mut stream, Infinite);

        self.stream = Some(stream);
        if let Ok(Message::ServerHello(_, world_state)) = server_hello {
            let mut world_state_lock = self.world_state.lock().unwrap();
            *world_state_lock = world_state;
        } else {
            panic!("Could not connect to server");
        }
    }

    pub fn update(&self) {
        let stream = self.stream.as_ref().expect("Stream not here :(");
        let mut command_stream = stream.try_clone().unwrap();
        let commands = self.commands.clone();

        // Command sender loop
        thread::spawn(move || {
            loop {
                let command = {
                    let mut commands = commands.lock().unwrap();
                    commands.pop_front()
                };
                command.map(|cmd| {
                    println!("Got command: {:?}", cmd);
                    //let cmd = Message::Command(Command::Move(0.into(), [100f64, 100f64]));
                    serialize_into(&mut command_stream, &Message::Command(cmd), Infinite)
                        .unwrap_or_else(|e|println!("Sending command failed: {}", e));
                });
                thread::sleep(time::Duration::from_millis(10));
            }
        });

        let mut game_state_stream = stream.try_clone().unwrap();
        let world_state = self.world_state.clone();
        thread::spawn(move || {
            loop {
                let game_state = deserialize_from(&mut game_state_stream,
                                                  Infinite);
                match game_state {
                    Ok(game) => {
                        //println!("{:?}", game);
                        let mut world_state_lock = world_state.lock().unwrap();
                        world_state_lock.game = game;

                    }
                    Err(e) => {
                        println!("{:?}", e);
                        thread::sleep(time::Duration::from_millis(200));
                    }
                }
            }
        });
    }
}

#[derive(Clone, Copy, Debug)]
pub enum State {
    Menu,
    Running,
}

pub struct App {
    pub gl: GlGraphics, // OpenGL drawing backend.
    pub world_state: Arc<Mutex<WorldState>>,
    pub units: Vec<Unit>,
    pub commands: Arc<Mutex<VecDeque<Command>>>,
    pub cursor: [f64; 2],
    pub state: State,
    menu: Menu,
}

impl App {
    pub fn new(gl: GlGraphics) -> App {
        App {
            gl: gl,
            world_state: Arc::new(Mutex::new(WorldState::new(0, 0))),
            units: vec![],
            commands: Arc::new(Mutex::new(VecDeque::new())),
            cursor: [0.0, 0.0],
            state: State::Menu,
            menu: Menu::new()
        }
    }

    pub fn start(&mut self) {
        let mut network_client = NetworkClient::new(("127.0.0.1", 8080), self.world_state.clone(), self.commands.clone());
        network_client.connect();
        network_client.update();
    }

    pub fn select(&mut self, position: [f64;2]) {
        for u in &mut self.units {
            u.selected = u.is_hit(position);
        };
    }

    fn render_game(&mut self, args: &RenderArgs, _: &mut GlyphCache) {
        use graphics::{polygon, clear};
        use graphics::Transformed;
        use graphics::types::Polygon;

        const FRONT_THICKNESS: f64 = 5.0;

        let units = &self.units;

        self.gl.draw(args.viewport(), |c, gl| {

            // Clear the screen.
            clear(BLACK, gl);

            for s in units.iter() {

                // Create a triangle polygon. The initial orientation is facing east.
                let triangle: Polygon = &s.get_shape();

                // Create a border on the front of the polygon. This is a trapezoid.
                // Because the angle of the trapezoid side is 22.5°, we know that `dx` is always `2 * dy`.
                let front: Polygon = &[
                    [s.size, s.size],                                           // Top right
                    [s.size, 0.0],                                                 // Bottom right
                    [s.size - FRONT_THICKNESS, FRONT_THICKNESS / 2.0],             // Bottom left
                    [s.size - FRONT_THICKNESS, s.size - FRONT_THICKNESS / 2.0], // Top left
                ];

                // Rotate the front to match the unit
                let transform_front = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // We don't need to apply any transformation to the units
                let transform_triangle = c.transform;

                // Draw the unit ORANGE if selected
                if s.selected {
                    polygon(ORANGE, triangle, transform_triangle, gl);
                    polygon(YELLOW, front, transform_front, gl);
                } else {
                    polygon(YELLOW, triangle, transform_triangle, gl);
                    polygon(ORANGE, front, transform_front, gl);
                }

            }
        });
    }

    pub fn render(&mut self, args: &RenderArgs, cache: &mut GlyphCache) {
        match self.state {
            State::Menu => self.menu.render(args, &mut self.gl, cache), //self.render_menu(args, cache),
            State::Running => self.render_game(args, cache),
        }
    }

    pub fn update(&mut self, _: &UpdateArgs) {
        let player = {
            let world_lock = self.world_state.lock().unwrap();
            world_lock.game.players.get(0).map(|v| v.clone())
        };
        if let Some(player) = player {
            for unit in player.units.iter() {
                self.units.get_mut(unit.id.0 as usize)
                    .map(|app_unit| {
                        app_unit.position = unit.position;
                        app_unit.rotation = unit.angle;
                    })
                    .or_else(|| {
                        self.units.push(Unit::new(unit.position.clone(), unit.angle));
                        None
                    });
            }
        }
    }

    pub fn on_button_press(&mut self, button: &Button) {
        match self.state {
            State::Menu => {
                match button {
                    &Button::Keyboard(Key::Up) => {
                        self.menu.previous();
                    }
                    &Button::Keyboard(Key::Down) => {
                        self.menu.next();
                    }
                    &Button::Keyboard(Key::Return) => {
                        match self.menu.get_selected_entry() {
                            menu::Entries::Start => {
                                self.start();
                                self.state = State::Running;
                            }
                            menu::Entries::Exit => {
                            }
                        }
                    }
                    _ => { }
                }
            }
            State::Running => {
                match button {
                    &Button::Keyboard(_) => { }
                    &Button::Mouse(button) => {
                        self.on_mouse_click(&button);
                    }
                    &Button::Controller(_) => { }
                }
            }
        };
    }

    pub fn on_mouse_click(&mut self, button: &MouseButton) {
        let cursor = self.cursor;
        match *button {
            MouseButton::Left  => self.select(cursor),
            MouseButton::Right => self.move_selected(cursor),
            _ => println!("Pressed mouse button '{:?}'", button),
        }
    }

    pub fn on_mouse_move(&mut self, cursor: [f64; 2]) {
        self.cursor = cursor;
    }

    pub fn move_selected(&mut self, position: [f64;2]) {
        for i in 0..self.units.len() {
            let s = &mut self.units[i];
            if s.selected {
                s.target = position;
                let dx = position[0] - s.position[0];
                let dy = position[1] - s.position[1];
                if dx.is_sign_negative() {
                    s.rotation = (dy / dx).atan() + PI;
                } else {
                    s.rotation = (dy / dx).atan();
                }
                let id = i as u32;
                let mut commands = self.commands.lock().unwrap();
                commands.push_back(Command::Move(id.into(), position));
                println!("dx: {}, dy: {}, new rotation: {}", dx, dy, s.rotation);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! SMTP client

use std::slice::Iter;
use std::ascii::AsciiExt;
use std::string::String;
use std::error::FromError;
use std::old_io::net::tcp::TcpStream;
use std::old_io::net::ip::{SocketAddr, ToSocketAddr};

use uuid::Uuid;

use tools::get_first_word;
use common::{CRLF, MESSAGE_ENDING, SMTP_PORT};
use response::Response;
use extension::Extension;
use error::{SmtpResult, ErrorKind};
use client::connecter::Connecter;
use client::server_info::ServerInfo;
use client::stream::ClientStream;
use sendable_email::SendableEmail;

pub mod server_info;
pub mod connecter;
pub mod stream;
pub mod authentication;

/// Represents the configuration of a client
#[derive(Debug)]
pub struct Configuration {
    /// Maximum connection reuse
    ///
    /// Zero means no limitation
    pub connection_reuse_count_limit: u16,
    /// Enable connection reuse
    pub enable_connection_reuse: bool,
    /// Maximum line length
    pub line_length_limit: u16,
    /// Name sent during HELO or EHLO
    pub hello_name: String,
}

/// Represents the state of a client
#[derive(Debug)]
pub struct State {
    /// Panic state
    pub panic: bool,
    /// Connection reuse counter
    pub connection_reuse_count: u16,
    /// Current message id
    pub current_message: Option<Uuid>,
}

/// Structure that implements the SMTP client
pub struct Client<S = TcpStream> {
    /// TCP stream between client and server
    /// Value is None before connection
    stream: Option<S>,
    /// Socket we are connecting to
    server_addr: SocketAddr,
    /// Information about the server
    /// Value is None before HELO/EHLO
    server_info: Option<ServerInfo>,
    /// Client variable states
    state: State,
    /// Configuration of the client
    configuration: Configuration,
}

macro_rules! try_smtp (
    ($err: expr, $client: ident) => ({
        match $err {
            Ok(val) => val,
            Err(err) => close_and_return_err!(err, $client),
        }
    })
);

macro_rules! close_and_return_err (
    ($err: expr, $client: ident) => ({
        if !$client.state.panic {
            $client.state.panic = true;
            $client.close();
        }
        return Err(FromError::from_error($err))
    })
);

macro_rules! with_code (
    ($result: ident, $codes: expr) => ({
        match $result {
            Ok(response) => {
                for code in $codes {
                    if *code == response.code {
                        return Ok(response);
                    }
                }
                Err(FromError::from_error(response))
            },
            Err(_) => $result,
        }
    })
);

impl<S = TcpStream> Client<S> {
    /// Creates a new SMTP client
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn new<A: ToSocketAddr>(addr: A) -> Client<S> {
        Client{
            stream: None,
            server_addr: addr.to_socket_addr().unwrap(),
            server_info: None,
            configuration: Configuration {
                connection_reuse_count_limit: 100,
                enable_connection_reuse: false,
                line_length_limit: 998,
                hello_name: "localhost".to_string(),
            },
            state: State {
                panic: false,
                connection_reuse_count: 0,
                current_message: None,
            },
        }
    }

    /// Creates a new local SMTP client to port 25
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn localhost() -> Client<S> {
        Client::new(("localhost", SMTP_PORT))
    }

    /// Set the name used during HELO or EHLO
    pub fn set_hello_name(&mut self, name: &str) {
        self.configuration.hello_name = name.to_string()
    }

    /// Set the maximum number of emails sent using one connection
    pub fn set_enable_connection_reuse(&mut self, enable: bool) {
        self.configuration.enable_connection_reuse = enable
    }

    /// Set the maximum number of emails sent using one connection
    pub fn set_connection_reuse_count_limit(&mut self, count: u16) {
        self.configuration.connection_reuse_count_limit = count
    }
}

impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
    /// Closes the SMTP transaction if possible
    pub fn close(&mut self) {
        let _ = self.quit();
    }

    /// Reset the client state
    pub fn reset(&mut self) {
        // Close the SMTP transaction if needed
        self.close();

        // Reset the client state
        self.stream = None;
        self.server_info = None;
        self.state.panic = false;
        self.state.connection_reuse_count = 0;
        self.state.current_message = None;
    }

    /// Sends an email
    pub fn send<T: SendableEmail>(&mut self, mut email: T) -> SmtpResult {

        // If there is a usable connection, test if the server answers and hello has been sent
        if self.state.connection_reuse_count > 0 {
            if self.noop().is_err() {
                self.reset();
            }
        }

        // Connect to the server if needed
        if self.stream.is_none() || self.server_info.is_none() {
            try!(self.connect());

            // Extended Hello or Hello if needed
            if let Err(error) = self.ehlo() {
                match error.kind {
                    ErrorKind::PermanentError(Response{code: 550, message: _}) => {
                        try_smtp!(self.helo(), self);
                    },
                    _ => {
                        try_smtp!(Err(error), self)
                    },
                };
            }

            // Print server information
            debug!("server {}", self.server_info.as_ref().unwrap());
        }

        self.state.current_message = Some(Uuid::new_v4());
        email.set_message_id(format!("<{}@{}>", self.state.current_message.as_ref().unwrap(),
            self.configuration.hello_name.clone()));

        let from_address = email.from_address();
        let to_addresses = email.to_addresses();
        let message = email.message();

        // Mail
        try_smtp!(self.mail(from_address.as_slice()), self);

        // Recipient
        // TODO Return rejected addresses
        // TODO Limit the number of recipients
        for to_address in to_addresses.iter() {
            try_smtp!(self.rcpt(to_address.as_slice()), self);
        }

        // Data
        try_smtp!(self.data(), self);

        // Message content
        self.message(message.as_slice())
    }

    /// Connects to the configured server
    pub fn connect(&mut self) -> SmtpResult {
        // Connect should not be called when the client is already connected
        if self.stream.is_some() {
            close_and_return_err!("The connection is already established", self);
        }

        // Try to connect
        self.stream = Some(try!(Connecter::connect(self.server_addr)));

        // Log the connection
        info!("connection established to {}",
            self.stream.as_mut().unwrap().peer_name().unwrap());

        self.stream.as_mut().unwrap().get_reply()//with_code([220].iter());
    }

    /// Sends an SMTP command
    fn command(&mut self, command: &str, expected_codes: Iter<u16>) -> SmtpResult {
        self.send_server(command, CRLF, expected_codes)
    }

    /// Sends content to the server, after checking the command sequence, and then
    /// updates the transaction state
    ///
    /// * If `message` is `None`, the given command will be formatted and sent to the server
    /// * If `message` is `Some(str)`, the `str` string will be sent to the server
    fn send_server(&mut self, content: &str, end: &str, expected_codes: Iter<u16>) -> SmtpResult {
        let result = self.stream.as_mut().unwrap().send_and_get_response(content, end);
        with_code!(result, expected_codes)
    }

    /// Checks if the server is connected using the NOOP SMTP command
    pub fn is_connected(&mut self) -> bool {
        self.noop().is_ok()
    }

    /// Send a HELO command and fills `server_info`
    pub fn helo(&mut self) -> SmtpResult {
        let hostname = self.configuration.hello_name.clone();
        let result = try!(self.command(format!("HELO {}", hostname).as_slice(), [250].iter()));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: vec!(),
            }
        );
        Ok(result)
    }

    /// Sends a EHLO command and fills `server_info`
    pub fn ehlo(&mut self) -> SmtpResult {
        let hostname = self.configuration.hello_name.clone();
        let result = try!(self.command(format!("EHLO {}", hostname).as_slice(), [250].iter()));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: Extension::parse_esmtp_response(
                                    result.message.as_ref().unwrap().as_slice()
                                ),
            }
        );
        Ok(result)
    }

    /// Sends a MAIL command
    pub fn mail(&mut self, address: &str) -> SmtpResult {

        // Generate an ID for the logs if None was provided
        if self.state.current_message.is_none() {
            self.state.current_message = Some(Uuid::new_v4());
        }

        // Checks message encoding according to the server's capability
        let options = match self.server_info.as_ref().unwrap().supports_feature(Extension::EightBitMime) {
            Some(_) => "BODY=8BITMIME",
            None => "",
        };

        let result = self.command(
            format!("MAIL FROM:<{}> {}", address, options).as_slice(), [250].iter()
        );

        if result.is_ok() {
            // Log the mail command
            info!("{}: from=<{}>", self.state.current_message.as_ref().unwrap(), address);
        }

        result
    }

    /// Sends a RCPT command
    pub fn rcpt(&mut self, address: &str) -> SmtpResult {
        let result = self.command(
            format!("RCPT TO:<{}>", address).as_slice(), [250, 251].iter());

        if result.is_ok() {
            // Log the rcpt command
            info!("{}: to=<{}>", self.state.current_message.as_ref().unwrap(), address);
        }

        result
    }

    /// Sends a DATA command
    pub fn data(&mut self) -> SmtpResult {
        self.command("DATA", [354].iter())
    }

    /// Sends the message content
    pub fn message(&mut self, message_content: &str) -> SmtpResult {
        // Check message encoding
        if !self.server_info.clone().unwrap().supports_feature(Extension::EightBitMime).is_some() {
            if !message_content.as_bytes().is_ascii() {
                close_and_return_err!("Server does not accepts UTF-8 strings", self);
            }
        }

        let result = self.send_server(message_content, MESSAGE_ENDING, [250].iter()); //250

        if result.is_ok() {
            // Increment the connection reuse counter
            self.state.connection_reuse_count = self.state.connection_reuse_count + 1;
            // Log the message
            info!("{}: conn_use={}, size={}, status=sent ({})", self.state.current_message.as_ref().unwrap(),
                self.state.connection_reuse_count, message_content.len(), result.as_ref().ok().unwrap());
        }

        self.state.current_message = None;

        // Test if we can reuse the existing connection
        if (!self.configuration.enable_connection_reuse) ||
            (self.state.connection_reuse_count == self.configuration.connection_reuse_count_limit) {
            self.reset();
        }

        result
    }

    /// Sends a QUIT command
    pub fn quit(&mut self) -> SmtpResult {
        self.command("QUIT", [221].iter())
    }

    /// Sends a RSET command
    pub fn rset(&mut self) -> SmtpResult {
        self.command("RSET", [250].iter())
    }

    /// Sends a NOOP command
    pub fn noop(&mut self) -> SmtpResult {
        self.command("NOOP", [250].iter())
    }

    /// Sends a VRFY command
    pub fn vrfy(&mut self, address: &str) -> SmtpResult {
        self.command(format!("VRFY {}", address).as_slice(), [250, 251, 252].iter())
    }

    /// Sends a EXPN command
    pub fn expn(&mut self, list: &str) -> SmtpResult {
        self.command(format!("EXPN {}", list).as_slice(), [250, 252].iter())
    }
}
<commit_msg>Generate uuid only if needed<commit_after>// Copyright 2014 Alexis Mousset. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! SMTP client

use std::slice::Iter;
use std::ascii::AsciiExt;
use std::string::String;
use std::error::FromError;
use std::old_io::net::tcp::TcpStream;
use std::old_io::net::ip::{SocketAddr, ToSocketAddr};

use log::LogLevel::Info;
use uuid::Uuid;

use tools::get_first_word;
use common::{CRLF, MESSAGE_ENDING, SMTP_PORT};
use response::Response;
use extension::Extension;
use error::{SmtpResult, ErrorKind};
use client::connecter::Connecter;
use client::server_info::ServerInfo;
use client::stream::ClientStream;
use sendable_email::SendableEmail;

pub mod server_info;
pub mod connecter;
pub mod stream;
pub mod authentication;

/// Represents the configuration of a client
#[derive(Debug)]
pub struct Configuration {
    /// Maximum connection reuse
    ///
    /// Zero means no limitation
    pub connection_reuse_count_limit: u16,
    /// Enable connection reuse
    pub enable_connection_reuse: bool,
    /// Maximum line length
    pub line_length_limit: u16,
    /// Name sent during HELO or EHLO
    pub hello_name: String,
}

/// Represents the state of a client
#[derive(Debug)]
pub struct State {
    /// Panic state
    pub panic: bool,
    /// Connection reuse counter
    pub connection_reuse_count: u16,
    /// Current message id
    pub current_message: Option<Uuid>,
}

/// Structure that implements the SMTP client
pub struct Client<S = TcpStream> {
    /// TCP stream between client and server
    /// Value is None before connection
    stream: Option<S>,
    /// Socket we are connecting to
    server_addr: SocketAddr,
    /// Information about the server
    /// Value is None before HELO/EHLO
    server_info: Option<ServerInfo>,
    /// Client variable states
    state: State,
    /// Configuration of the client
    configuration: Configuration,
}

macro_rules! try_smtp (
    ($err: expr, $client: ident) => ({
        match $err {
            Ok(val) => val,
            Err(err) => close_and_return_err!(err, $client),
        }
    })
);

macro_rules! close_and_return_err (
    ($err: expr, $client: ident) => ({
        if !$client.state.panic {
            $client.state.panic = true;
            $client.close();
        }
        return Err(FromError::from_error($err))
    })
);

macro_rules! with_code (
    ($result: ident, $codes: expr) => ({
        match $result {
            Ok(response) => {
                for code in $codes {
                    if *code == response.code {
                        return Ok(response);
                    }
                }
                Err(FromError::from_error(response))
            },
            Err(_) => $result,
        }
    })
);

impl<S = TcpStream> Client<S> {
    /// Creates a new SMTP client
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn new<A: ToSocketAddr>(addr: A) -> Client<S> {
        Client{
            stream: None,
            server_addr: addr.to_socket_addr().unwrap(),
            server_info: None,
            configuration: Configuration {
                connection_reuse_count_limit: 100,
                enable_connection_reuse: false,
                line_length_limit: 998,
                hello_name: "localhost".to_string(),
            },
            state: State {
                panic: false,
                connection_reuse_count: 0,
                current_message: None,
            },
        }
    }

    /// Creates a new local SMTP client to port 25
    ///
    /// It does not connects to the server, but only create the `Client`
    pub fn localhost() -> Client<S> {
        Client::new(("localhost", SMTP_PORT))
    }

    /// Set the name used during HELO or EHLO
    pub fn set_hello_name(&mut self, name: &str) {
        self.configuration.hello_name = name.to_string()
    }

    /// Set the maximum number of emails sent using one connection
    pub fn set_enable_connection_reuse(&mut self, enable: bool) {
        self.configuration.enable_connection_reuse = enable
    }

    /// Set the maximum number of emails sent using one connection
    pub fn set_connection_reuse_count_limit(&mut self, count: u16) {
        self.configuration.connection_reuse_count_limit = count
    }
}

impl<S: Connecter + ClientStream + Clone = TcpStream> Client<S> {
    /// Closes the SMTP transaction if possible
    pub fn close(&mut self) {
        let _ = self.quit();
    }

    /// Reset the client state
    pub fn reset(&mut self) {
        // Close the SMTP transaction if needed
        self.close();

        // Reset the client state
        self.stream = None;
        self.server_info = None;
        self.state.panic = false;
        self.state.connection_reuse_count = 0;
        self.state.current_message = None;
    }

    /// Sends an email
    pub fn send<T: SendableEmail>(&mut self, mut email: T) -> SmtpResult {

        // If there is a usable connection, test if the server answers and hello has been sent
        if self.state.connection_reuse_count > 0 {
            if self.noop().is_err() {
                self.reset();
            }
        }

        // Connect to the server if needed
        if self.stream.is_none() || self.server_info.is_none() {
            try!(self.connect());

            // Extended Hello or Hello if needed
            if let Err(error) = self.ehlo() {
                match error.kind {
                    ErrorKind::PermanentError(Response{code: 550, message: _}) => {
                        try_smtp!(self.helo(), self);
                    },
                    _ => {
                        try_smtp!(Err(error), self)
                    },
                };
            }

            // Print server information
            debug!("server {}", self.server_info.as_ref().unwrap());
        }

        self.state.current_message = Some(Uuid::new_v4());
        email.set_message_id(format!("<{}@{}>", self.state.current_message.as_ref().unwrap(),
            self.configuration.hello_name.clone()));

        let from_address = email.from_address();
        let to_addresses = email.to_addresses();
        let message = email.message();

        // Mail
        try_smtp!(self.mail(from_address.as_slice()), self);

        // Recipient
        // TODO Return rejected addresses
        // TODO Limit the number of recipients
        for to_address in to_addresses.iter() {
            try_smtp!(self.rcpt(to_address.as_slice()), self);
        }

        // Data
        try_smtp!(self.data(), self);

        // Message content
        self.message(message.as_slice())
    }

    /// Connects to the configured server
    pub fn connect(&mut self) -> SmtpResult {
        // Connect should not be called when the client is already connected
        if self.stream.is_some() {
            close_and_return_err!("The connection is already established", self);
        }

        // Try to connect
        self.stream = Some(try!(Connecter::connect(self.server_addr)));

        // Log the connection
        info!("connection established to {}",
            self.stream.as_mut().unwrap().peer_name().unwrap());

        self.stream.as_mut().unwrap().get_reply()//with_code([220].iter());
    }

    /// Sends an SMTP command
    fn command(&mut self, command: &str, expected_codes: Iter<u16>) -> SmtpResult {
        self.send_server(command, CRLF, expected_codes)
    }

    /// Sends content to the server, after checking the command sequence, and then
    /// updates the transaction state
    ///
    /// * If `message` is `None`, the given command will be formatted and sent to the server
    /// * If `message` is `Some(str)`, the `str` string will be sent to the server
    fn send_server(&mut self, content: &str, end: &str, expected_codes: Iter<u16>) -> SmtpResult {
        let result = self.stream.as_mut().unwrap().send_and_get_response(content, end);
        with_code!(result, expected_codes)
    }

    /// Checks if the server is connected using the NOOP SMTP command
    pub fn is_connected(&mut self) -> bool {
        self.noop().is_ok()
    }

    /// Send a HELO command and fills `server_info`
    pub fn helo(&mut self) -> SmtpResult {
        let hostname = self.configuration.hello_name.clone();
        let result = try!(self.command(format!("HELO {}", hostname).as_slice(), [250].iter()));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: vec!(),
            }
        );
        Ok(result)
    }

    /// Sends a EHLO command and fills `server_info`
    pub fn ehlo(&mut self) -> SmtpResult {
        let hostname = self.configuration.hello_name.clone();
        let result = try!(self.command(format!("EHLO {}", hostname).as_slice(), [250].iter()));
        self.server_info = Some(
            ServerInfo{
                name: get_first_word(result.message.as_ref().unwrap().as_slice()).to_string(),
                esmtp_features: Extension::parse_esmtp_response(
                                    result.message.as_ref().unwrap().as_slice()
                                ),
            }
        );
        Ok(result)
    }

    /// Sends a MAIL command
    pub fn mail(&mut self, address: &str) -> SmtpResult {
        // Checks message encoding according to the server's capability
        let options = match self.server_info.as_ref().unwrap().supports_feature(Extension::EightBitMime) {
            Some(_) => "BODY=8BITMIME",
            None => "",
        };

        let result = self.command(
            format!("MAIL FROM:<{}> {}", address, options).as_slice(), [250].iter()
        );

        if result.is_ok() {
            // Log the mail command
            if log_enabled!(Info) {
                // Generate an ID for the logs if None was provided
                if self.state.current_message.is_none() {
                    self.state.current_message = Some(Uuid::new_v4());
                }
                info!("{}: from=<{}>", self.state.current_message.as_ref().unwrap(), address);
            }
        }

        result
    }

    /// Sends a RCPT command
    pub fn rcpt(&mut self, address: &str) -> SmtpResult {
        let result = self.command(
            format!("RCPT TO:<{}>", address).as_slice(), [250, 251].iter());

        if result.is_ok() {
            // Log the rcpt command
            info!("{}: to=<{}>", self.state.current_message.as_ref().unwrap(), address);
        }

        result
    }

    /// Sends a DATA command
    pub fn data(&mut self) -> SmtpResult {
        self.command("DATA", [354].iter())
    }

    /// Sends the message content
    pub fn message(&mut self, message_content: &str) -> SmtpResult {
        // Check message encoding
        if !self.server_info.clone().unwrap().supports_feature(Extension::EightBitMime).is_some() {
            if !message_content.as_bytes().is_ascii() {
                close_and_return_err!("Server does not accepts UTF-8 strings", self);
            }
        }

        let result = self.send_server(message_content, MESSAGE_ENDING, [250].iter()); //250

        if result.is_ok() {
            // Increment the connection reuse counter
            self.state.connection_reuse_count = self.state.connection_reuse_count + 1;
            // Log the message
            info!("{}: conn_use={}, size={}, status=sent ({})", self.state.current_message.as_ref().unwrap(),
                self.state.connection_reuse_count, message_content.len(), result.as_ref().ok().unwrap());
        }

        self.state.current_message = None;

        // Test if we can reuse the existing connection
        if (!self.configuration.enable_connection_reuse) ||
            (self.state.connection_reuse_count == self.configuration.connection_reuse_count_limit) {
            self.reset();
        }

        result
    }

    /// Sends a QUIT command
    pub fn quit(&mut self) -> SmtpResult {
        self.command("QUIT", [221].iter())
    }

    /// Sends a RSET command
    pub fn rset(&mut self) -> SmtpResult {
        self.command("RSET", [250].iter())
    }

    /// Sends a NOOP command
    pub fn noop(&mut self) -> SmtpResult {
        self.command("NOOP", [250].iter())
    }

    /// Sends a VRFY command
    pub fn vrfy(&mut self, address: &str) -> SmtpResult {
        self.command(format!("VRFY {}", address).as_slice(), [250, 251, 252].iter())
    }

    /// Sends a EXPN command
    pub fn expn(&mut self, list: &str) -> SmtpResult {
        self.command(format!("EXPN {}", list).as_slice(), [250, 252].iter())
    }
}
<|endoftext|>


<commit_before>//! Defines the `MoveGenerator` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use board::*;
use moves::*;
use value::*;
use evaluator::Evaluator;
use bitsets::*;
use utils::BoardGeometry;

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position and can:
///
/// * Generate all legal moves, or a subset of all legal moves in the
///   current position.
///
/// * Perform static exchange evaluation for the generated moves.
///
/// * Play a selected move and take it back.
///
/// * Provide a static evaluator bound to the current position.
///
/// * Calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method will be relatively slow if the
    /// implementation calculates the hash value "from
    /// scratch". Inspect the implementation before using `hash` in
    /// time-critical paths. (See `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_all`, `generate_forcing`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < PIECE_NONE);
        debug_assert!(m.captured_piece() <= PIECE_NONE);
        const PIECE_VALUES: [Value; 8] = [10000, 975, 500, 325, 325, 100, 0, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        unsafe {
            let geometry = BoardGeometry::get();
            let behind_blocker: &[Bitboard; 64] = geometry.squares_behind_blocker
                                                          .get_unchecked(exchange_square);
            let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
            let color: &[Bitboard; 2] = &self.board().pieces.color;
            let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
            let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

            // These variables will be updated on each capture:
            let mut us = self.board().to_move;
            let mut depth = 0;
            let mut piece;
            let mut orig_square_bb = 1 << m.orig_square();
            let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                              self.attacks_to(BLACK, exchange_square);

            // The `gain` array will hold the total material gained at
            // each `depth`, from the viewpoint of the side that made the
            // last capture (`us`).
            let mut gain: [Value; 34] = uninitialized();
            gain[0] = if m.move_type() == MOVE_PROMOTION {
                piece = Move::piece_from_aux_data(m.aux_data());
                PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
            } else {
                piece = m.played_piece();
                *PIECE_VALUES.get_unchecked(m.captured_piece())
            };

            // Examine the possible exchanges, fill the `gain` array.
            'exchange: while orig_square_bb != 0 {
                let current_gain = *gain.get_unchecked(depth);

                // Store a speculative value that will be used if the
                // captured piece happens to be defended.
                let speculative_gain: &mut Value = gain.get_unchecked_mut(depth + 1);
                *speculative_gain = *PIECE_VALUES.get_unchecked(piece) - current_gain;

                if max(-current_gain, *speculative_gain) < 0 {
                    // The side that made the last capture wins even if
                    // the captured piece happens to be defended. So, we
                    // stop here to save precious CPU cycles. Note that
                    // here we may happen to return an incorrect SEE
                    // value, but the sign will be correct, which is by
                    // far the most important information.
                    break;
                }

                // Register that capturing piece's origin square is now vacant.
                attackers_and_defenders &= !orig_square_bb;

                // Consider adding new attackers/defenders, now that
                // capturing piece's origin square is vacant.
                let behind = self.board().occupied &
                             *behind_blocker.get_unchecked(bsf(orig_square_bb));
                if behind & (straight_sliders | diag_sliders) != 0 {
                    attackers_and_defenders |=
                        match behind & straight_sliders &
                              geometry.attacks_from_unsafe(ROOK, exchange_square, behind) {
                            0 => {
                                // Not a straight slider, possibly a diagonal slider.
                                behind & diag_sliders &
                                geometry.attacks_from_unsafe(BISHOP, exchange_square, behind)
                            }
                            bb => {
                                // A straight slider.
                                bb
                            }
                        };
                }

                // Change the side to move.
                us ^= 1;

                // Find the next piece to enter the exchange. (The least
                // valuable piece belonging to the side to move.)
                let candidates = attackers_and_defenders & *color.get_unchecked(us);
                if candidates != 0 {
                    for p in (KING..PIECE_NONE).rev() {
                        let bb = candidates & piece_type[p];
                        if bb != 0 {
                            depth += 1;
                            piece = p;
                            orig_square_bb = lsb(bb);
                            continue 'exchange;
                        }
                    }
                }
                break 'exchange;
            }

            // Negamax the `gain` array for the final static exchange
            // evaluation. (The `gain` array actually represents an unary
            // tree, at each node of which the player can either continue
            // the exchange or back off.)
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
            gain[0]
        }
    }
}
<commit_msg>fix minor regression coused by removing may_xray<commit_after>//! Defines the `MoveGenerator` trait.

use std::mem::uninitialized;
use std::cmp::max;
use uci::SetOption;
use board::*;
use moves::*;
use value::*;
use evaluator::Evaluator;
use bitsets::*;
use utils::BoardGeometry;

/// A trait for move generators.
///
/// A `MoveGenerator` holds a chess position and can:
///
/// * Generate all legal moves, or a subset of all legal moves in the
///   current position.
///
/// * Perform static exchange evaluation for the generated moves.
///
/// * Play a selected move and take it back.
///
/// * Provide a static evaluator bound to the current position.
///
/// * Calculate Zobrist hashes.
///
/// **Important note:** `MoveGenerator` is unaware of repeating
/// positions and rule-50.
pub trait MoveGenerator: Sized + Send + Clone + SetOption {
    /// The type of static evaluator that the implementation works
    /// with.
    type Evaluator: Evaluator;

    /// Creates a new instance, consuming the supplied `Board`
    /// instance.
    ///
    /// Returns `None` if the position is illegal.
    fn from_board(board: Board) -> Option<Self>;

    /// Returns the Zobrist hash value for the underlying `Board`
    /// instance.
    ///
    /// Zobrist hashing is a technique to transform a board position
    /// into a number of a fixed length, with an equal distribution
    /// over all possible numbers, invented by Albert Zobrist. The key
    /// property of this method is that two similar positions generate
    /// entirely different hash numbers.
    ///
    /// **Important note:** This method will be relatively slow if the
    /// implementation calculates the hash value "from
    /// scratch". Inspect the implementation before using `hash` in
    /// time-critical paths. (See `do_move`.)
    fn hash(&self) -> u64;

    /// Returns a reference to the underlying `Board` instance.
    #[inline(always)]
    fn board(&self) -> &Board;

    /// Returns a bitboard with all pieces of color `us` that attack
    /// `square`.
    fn attacks_to(&self, us: Color, square: Square) -> Bitboard;

    /// Returns a bitboard with all enemy pieces that attack the king.
    ///
    /// **Important note:** The bitboard of checkers is calculated on
    /// the first call to `checkers`, and is stored in case another
    /// call is made before doing/undoing any moves. In that case
    /// `checkers` returns the saved bitboard instead of
    /// re-calculating it, thus saving time.
    fn checkers(&self) -> Bitboard;

    /// Returns a reference to a static evaluator bound to the current
    /// position.
    fn evaluator(&self) -> &Self::Evaluator;

    /// Generates all legal moves, possibly including some
    /// pseudo-legal moves too.
    ///
    /// The moves are added to `moves`. All generated moves with
    /// pieces other than the king will be legal. Some of the
    /// generated king's moves may be illegal because the destination
    /// square is under attack. This arrangement has two important
    /// advantages:
    ///
    /// * `do_move` can do its work without knowing the set of
    ///   checkers and pinned pieces, so there is no need to keep
    ///   those around.
    ///
    /// * A beta cut-off may make the verification that king's
    ///   destination square is not under attack unnecessary, thus
    ///   saving time.
    ///
    /// **Note:** A pseudo-legal move is a move that is otherwise
    /// legal, except it might leave the king in check.
    fn generate_all<T: AddMove>(&self, moves: &mut T);

    /// Generates moves for the quiescence search.
    ///
    /// The moves are added to `moves`. This method always generates a
    /// **subset** of the moves generated by `generate_all`:
    ///
    /// * If the king is in check, all legal moves are included.
    ///
    /// * Captures and pawn promotions to queen are always included.
    ///
    /// * If `generate_checks` is `true`, moves that give check are
    ///   included too. Discovered checks and checks given by castling
    ///   can be omitted for speed.
    fn generate_forcing<T: AddMove>(&self, generate_checks: bool, moves: &mut T);

    /// Checks if `move_digest` represents a pseudo-legal move.
    ///
    /// If a move `m` exists that would be generated by
    /// `generate_all` if called for the current position on the
    /// board, and for that move `m.digest() == move_digest`, this
    /// method will return `Some(m)`. Otherwise it will return
    /// `None`. This is useful when playing moves from the
    /// transposition table, without calling `generate_all`.
    fn try_move_digest(&self, move_digest: MoveDigest) -> Option<Move>;

    /// Returns a null move.
    ///
    /// "Null move" is a pseudo-move that changes only the side to
    /// move. It is sometimes useful to include a speculative null
    /// move in the search tree so as to achieve more aggressive
    /// pruning. Null moves are represented as king's moves for which
    /// the origin and destination squares are the same.
    fn null_move(&self) -> Move;

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and an `u64` value is returned, which should
    /// be XOR-ed with old board's hash value to obtain new board's
    /// hash value. If the move is illegal, `None` is returned without
    /// updating the board. The move passed to this method **must**
    /// have been generated by `generate_all`, `generate_forcing`,
    /// `try_move_digest`, or `null_move` methods for the current
    /// position on the board.
    ///
    /// The moves generated by the `null_move` method are
    /// exceptions. For them `do_move` will return `None` if and only
    /// if the king is in check.
    fn do_move(&mut self, m: Move) -> Option<u64>;

    /// Takes back last played move.
    ///
    /// The move passed to this method **must** be the last move passed
    /// to `do_move`.
    fn undo_move(&mut self, m: Move);

    /// Returns the likely evaluation change (material) to be lost or
    /// gained as a result of a given move.
    ///
    /// This method performs static exchange evaluation (SEE). It
    /// examines the consequence of a series of exchanges on the
    /// destination square after a given move. A positive returned
    /// value indicates a "winning" move. For example, "PxQ" will
    /// always be a win, since the pawn side can choose to stop the
    /// exchange after its pawn is recaptured, and still be ahead. SEE
    /// is just an evaluation calculated without actually trying moves
    /// on the board, and therefore the returned value might be
    /// incorrect.
    ///
    /// The move passed to this method must have been generated by
    /// `generate_all`, `generate_forcing`, `try_move_digest`, or
    /// `null_move` methods for the current position on the board.
    fn evaluate_move(&self, m: Move) -> Value {
        debug_assert!(m.played_piece() < PIECE_NONE);
        debug_assert!(m.captured_piece() <= PIECE_NONE);
        const PIECE_VALUES: [Value; 8] = [10000, 975, 500, 325, 325, 100, 0, 0];

        // This is the square on which all the action takes place.
        let exchange_square = m.dest_square();

        unsafe {
            let geometry = BoardGeometry::get();
            let behind_blocker: &[Bitboard; 64] = geometry.squares_behind_blocker
                                                          .get_unchecked(exchange_square);
            let piece_type: &[Bitboard; 6] = &self.board().pieces.piece_type;
            let color: &[Bitboard; 2] = &self.board().pieces.color;
            let straight_sliders = piece_type[QUEEN] | piece_type[ROOK];
            let diag_sliders = piece_type[QUEEN] | piece_type[BISHOP];

            // These variables will be updated on each capture:
            let mut us = self.board().to_move;
            let mut depth = 0;
            let mut piece;
            let mut orig_square_bb = 1 << m.orig_square();
            let mut attackers_and_defenders = self.attacks_to(WHITE, exchange_square) |
                                              self.attacks_to(BLACK, exchange_square);

            // The `gain` array will hold the total material gained at
            // each `depth`, from the viewpoint of the side that made the
            // last capture (`us`).
            let mut gain: [Value; 34] = uninitialized();
            gain[0] = if m.move_type() == MOVE_PROMOTION {
                piece = Move::piece_from_aux_data(m.aux_data());
                PIECE_VALUES[m.captured_piece()] + PIECE_VALUES[piece] - PIECE_VALUES[PAWN]
            } else {
                piece = m.played_piece();
                *PIECE_VALUES.get_unchecked(m.captured_piece())
            };

            // Examine the possible exchanges, fill the `gain` array.
            'exchange: while orig_square_bb != 0 {
                let current_gain = *gain.get_unchecked(depth);

                // Store a speculative value that will be used if the
                // captured piece happens to be defended.
                let speculative_gain: &mut Value = gain.get_unchecked_mut(depth + 1);
                *speculative_gain = *PIECE_VALUES.get_unchecked(piece) - current_gain;

                if max(-current_gain, *speculative_gain) < 0 {
                    // The side that made the last capture wins even if
                    // the captured piece happens to be defended. So, we
                    // stop here to save precious CPU cycles. Note that
                    // here we may happen to return an incorrect SEE
                    // value, but the sign will be correct, which is by
                    // far the most important information.
                    break;
                }

                // Register that capturing piece's origin square is now vacant.
                attackers_and_defenders &= !orig_square_bb;

                // Consider adding new attackers/defenders, now that
                // capturing piece's origin square is vacant.
                let behind = self.board().occupied &
                             *behind_blocker.get_unchecked(bsf(orig_square_bb));
                if behind & (straight_sliders | diag_sliders) != 0 && piece != KING {
                    attackers_and_defenders |=
                        match behind & straight_sliders &
                              geometry.attacks_from_unsafe(ROOK, exchange_square, behind) {
                            0 => {
                                // Not a straight slider, possibly a diagonal slider.
                                behind & diag_sliders &
                                geometry.attacks_from_unsafe(BISHOP, exchange_square, behind)
                            }
                            bb => {
                                // A straight slider.
                                bb
                            }
                        };
                }

                // Change the side to move.
                us ^= 1;

                // Find the next piece to enter the exchange. (The least
                // valuable piece belonging to the side to move.)
                let candidates = attackers_and_defenders & *color.get_unchecked(us);
                if candidates != 0 {
                    for p in (KING..PIECE_NONE).rev() {
                        let bb = candidates & piece_type[p];
                        if bb != 0 {
                            depth += 1;
                            piece = p;
                            orig_square_bb = lsb(bb);
                            continue 'exchange;
                        }
                    }
                }
                break 'exchange;
            }

            // Negamax the `gain` array for the final static exchange
            // evaluation. (The `gain` array actually represents an unary
            // tree, at each node of which the player can either continue
            // the exchange or back off.)
            while depth > 0 {
                *gain.get_unchecked_mut(depth - 1) = -max(-*gain.get_unchecked(depth - 1),
                                                          *gain.get_unchecked(depth));
                depth -= 1;
            }
            gain[0]
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

// #[no_mangle]
// pub extern "C" fn some_new_fn() -> c_int {
//     println!("Whatadfsasdf");
//     65 as c_int
// }

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
#[no_mangle]
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");
    println!("Rust - connect");

    78 as c_int

    // let mut r_address;
    // unsafe {
    //     r_address = CStr::from_ptr(address);
    // }
    // let s_address = r_address.to_bytes();
    // let host_address = match str::from_utf8(s_address) {
    //     Ok(safe_str) => safe_str,
    //     Err(_) => {
    //         println!("Invalid host address");
    //         return -1 as c_int;
    //     }
    // };
    //
    // // Create and register a way to kill this client
    // let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    // let kill_tx = k_tx.clone();
    // let mut k_tx_ptr = Box::new(k_tx);
    // unsafe {
    //     register_stop_tx(&mut *k_tx_ptr);
    // }
    //
    // // Writer thread's channel
    // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    // let mut w_tx_ptr = Box::new(w_tx);
    // unsafe {
    //     register_writer_tx(&mut *w_tx_ptr);
    // }
    //
    // println!("Attempting connect to: {}", host_address);
    //
    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();
    //
    // // Exit out in standard C fashion
    // 0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

#[no_mangle]
pub extern "C" fn some_new_fn() -> c_int {
    println!("Whatadfsasdf");
    65 as c_int
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
// #[no_mangle]
// pub extern "C" fn connect(address: *const c_char,
//     handler: extern fn(*const c_char, c_int),
//     on_connect_handler: extern fn(),
//     on_disconnect_handler: extern fn()) -> c_int {
//
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//
//
//     78 as c_int
//
//
//     // let mut r_address;
//     // unsafe {
//     //     r_address = CStr::from_ptr(address);
//     // }
//     // let s_address = r_address.to_bytes();
//     // let host_address = match str::from_utf8(s_address) {
//     //     Ok(safe_str) => safe_str,
//     //     Err(_) => {
//     //         println!("Invalid host address");
//     //         return -1 as c_int;
//     //     }
//     // };
//     //
//     // // Create and register a way to kill this client
//     // let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
//     // let kill_tx = k_tx.clone();
//     // let mut k_tx_ptr = Box::new(k_tx);
//     // unsafe {
//     //     register_stop_tx(&mut *k_tx_ptr);
//     // }
//     //
//     // // Writer thread's channel
//     // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
//     // let mut w_tx_ptr = Box::new(w_tx);
//     // unsafe {
//     //     register_writer_tx(&mut *w_tx_ptr);
//     // }
//     //
//     // println!("Attempting connect to: {}", host_address);
//     //
//     // let result = TcpStream::connect(host_address);
//     // if result.is_err() {
//     //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
//     //     return -1 as c_int;
//     // }
//     // println!("Connected");
//     // on_connect_handler();
//     //
//     // let stream = result.unwrap();
//     // let client = Bstream::new(stream);
//     //
//     // let r_client = client.clone();
//     // let r_kill_tx = kill_tx.clone();
//     //
//     // let w_client = client.clone();
//     // let w_kill_tx = kill_tx.clone();
//     //
//     // // Start the reader thread
//     // thread::Builder::new()
//     //     .name("ReaderThread".to_string())
//     //     .spawn(move||{
//     //         reader_thread(r_client, handler, r_kill_tx)
//     //     }).unwrap();
//     //
//     // // Start the writer thread
//     // thread::Builder::new()
//     //     .name("WriterThread".to_string())
//     //     .spawn(move||{
//     //         writer_thread(w_rx, w_client, w_kill_tx)
//     //     }).unwrap();
//     //
//     // // Wait for the kill signal
//     // match kill_rx.recv() {
//     //     Ok(_) => { }
//     //     Err(e) => {
//     //         println!("Error on kill channel: {}", e);
//     //         return -1 as c_int;
//     //     }
//     // };
//     // on_disconnect_handler();
//     //
//     // // Exit out in standard C fashion
//     // 0 as c_int
// }

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>//! Common types for the [push notifications module][push]
//!
//! [push]: https://matrix.org/docs/spec/client_server/r0.6.0#id89

use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue;

mod tweak_serde;

/// The `set_tweak` action.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(from = "tweak_serde::Tweak", into = "tweak_serde::Tweak")]
pub enum Tweak {
    /// A string representing the sound to be played when this notification arrives.
    ///
    /// A value of "default" means to play a default sound. A device may choose to alert the user by
    /// some other means if appropriate, eg. vibration.
    Sound(String),

    /// A boolean representing whether or not this message should be highlighted in the UI.
    ///
    /// This will normally take the form of presenting the message in a different color and/or
    /// style. The UI might also be adjusted to draw particular attention to the room in which the
    /// event occurred. If a `highlight` tweak is given with no value, its value is defined to be
    /// `true`. If no highlight tweak is given at all then the value of `highlight` is defined to be
    /// `false`.
    Highlight(#[serde(default = "ruma_serde::default_true")] bool),

    /// A custom tweak
    Custom {
        /// The name of the custom tweak (`set_tweak` field)
        name: String,

        /// The value of the custom tweak
        value: Box<RawJsonValue>,
    },
}
<commit_msg>Add push::Action<commit_after>//! Common types for the [push notifications module][push]
//!
//! [push]: https://matrix.org/docs/spec/client_server/r0.6.0#id89

use std::fmt::{self, Formatter};

use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_json::value::RawValue as RawJsonValue;

mod tweak_serde;

/// This represents the different actions that should be taken when a rule is matched, and
/// controls how notifications are delivered to the client.
///
/// See https://matrix.org/docs/spec/client_server/r0.6.0#actions for details.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Action {
    /// Causes matching events to generate a notification.
    Notify,

    /// Prevents matching events from generating a notification.
    DontNotify,

    /// Behaves like notify but homeservers may choose to coalesce multiple events
    /// into a single notification.
    Coalesce,

    /// Sets an entry in the 'tweaks' dictionary sent to the push gateway.
    SetTweak(Tweak),
}

/// The `set_tweak` action.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(from = "tweak_serde::Tweak", into = "tweak_serde::Tweak")]
pub enum Tweak {
    /// A string representing the sound to be played when this notification arrives.
    ///
    /// A value of "default" means to play a default sound. A device may choose to alert the user by
    /// some other means if appropriate, eg. vibration.
    Sound(String),

    /// A boolean representing whether or not this message should be highlighted in the UI.
    ///
    /// This will normally take the form of presenting the message in a different color and/or
    /// style. The UI might also be adjusted to draw particular attention to the room in which the
    /// event occurred. If a `highlight` tweak is given with no value, its value is defined to be
    /// `true`. If no highlight tweak is given at all then the value of `highlight` is defined to be
    /// `false`.
    Highlight(#[serde(default = "ruma_serde::default_true")] bool),

    /// A custom tweak
    Custom {
        /// The name of the custom tweak (`set_tweak` field)
        name: String,

        /// The value of the custom tweak
        value: Box<RawJsonValue>,
    },
}

impl<'de> Deserialize<'de> for Action {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        use serde::de::{MapAccess, Visitor};

        struct ActionVisitor;
        impl<'de> Visitor<'de> for ActionVisitor {
            type Value = Action;

            fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
                write!(formatter, "a valid action object")
            }

            /// Match a simple action type
            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                match v {
                    "notify" => Ok(Action::Notify),
                    "dont_notify" => Ok(Action::DontNotify),
                    "coalesce" => Ok(Action::Coalesce),
                    s => Err(E::unknown_variant(
                        &s,
                        &["notify", "dont_notify", "coalesce"],
                    )),
                }
            }

            /// Match the more complex set_tweaks action object as a key-value map
            fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
            where
                A: MapAccess<'de>,
            {
                Tweak::deserialize(serde::de::value::MapAccessDeserializer::new(map))
                    .map(Action::SetTweak)
            }
        }

        deserializer.deserialize_any(ActionVisitor)
    }
}

impl Serialize for Action {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match self {
            Action::Notify => serializer.serialize_unit_variant("Action", 0, "notify"),
            Action::DontNotify => serializer.serialize_unit_variant("Action", 1, "dont_notify"),
            Action::Coalesce => serializer.serialize_unit_variant("Action", 2, "coalesce"),
            Action::SetTweak(kind) => kind.serialize(serializer),
        }
    }
}
<|endoftext|>


<commit_before>pub type Coordinate = [i32; 2];

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction {
    North,
    East,
    South,
    West,
}

pub struct Grid {
    cell_size: [::Float; 2],
}

impl Grid {
    pub fn new(size: ::Float) -> Grid {
        Grid {
            cell_size: [size, size],
        }
    }
}

impl ::Grid for Grid {
    type Coordinate = Coordinate;
    type Direction = Direction;

    fn get_cell_center(&self, c: Coordinate) -> ::Point {
        [(c[0] as f32 + 0.5) * self.cell_size[0],
         (c[1] as f32 + 0.5) * self.cell_size[1],
         0.0]
    }

    fn get_coordinate(&self, p: &::Point) -> Coordinate {
        [(p[0] / self.cell_size[0]) as i32,
         (p[1] / self.cell_size[1]) as i32]
    }

    fn get_neighbour(&self, c: Coordinate, d: Direction) -> Coordinate {
        match d {
            Direction::North => [c[0], c[1]+1],
            Direction::East  => [c[0]+1, c[1]],
            Direction::South => [c[0], c[1]-1],
            Direction::West  => [c[0]-1, c[1]],
        }
    }

    fn fold_neighbours<U, F: Fn(U, Coordinate, Direction) -> U>(&self, _: Coordinate, _: F, u: U) -> U {
        u //TODO
    }

    fn fold_in_radius<U, F: Fn(U, Coordinate) -> U>(&self, _: Coordinate, _: ::Float, _: F, u: U) -> U {
        u //TODO
    }
}
<commit_msg>Implemented fold_() methods for the quad grid<commit_after>pub type Coordinate = [i32; 2];

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction {
    North,
    East,
    South,
    West,
}

#[derive(Clone, Debug)]
pub struct Grid {
    cell_size: [::Float; 2],
}

impl Grid {
    pub fn new(size: ::Float) -> Grid {
        Grid {
            cell_size: [size, size],
        }
    }
}

impl ::Grid for Grid {
    type Coordinate = Coordinate;
    type Direction = Direction;

    fn get_cell_center(&self, c: Coordinate) -> ::Point {
        [(c[0] as f32 + 0.5) * self.cell_size[0],
         (c[1] as f32 + 0.5) * self.cell_size[1],
         0.0]
    }

    fn get_coordinate(&self, p: &::Point) -> Coordinate {
        [(p[0] / self.cell_size[0]) as i32,
         (p[1] / self.cell_size[1]) as i32]
    }

    fn get_neighbour(&self, c: Coordinate, d: Direction) -> Coordinate {
        match d {
            Direction::North => [c[0], c[1]+1],
            Direction::East  => [c[0]+1, c[1]],
            Direction::South => [c[0], c[1]-1],
            Direction::West  => [c[0]-1, c[1]],
        }
    }

    fn fold_neighbours<U, F: Fn(U, Coordinate, Direction) -> U>(&self, coord: Coordinate, u: U, fun: F) -> U {
        [Direction::North, Direction::East, Direction::South, Direction::West]
            .iter().fold(u, |u, &d| fun(u, self.get_neighbour(coord, d), d))
    }

    fn fold_in_radius<U, F: Fn(U, Coordinate) -> U>(&self, coord: Coordinate, radius: ::Float, mut u: U, fun: F) -> U {
        let ext_x = (radius / self.cell_size[0]) as i32;
        let ext_y = (radius / self.cell_size[1]) as i32;
        for x in coord[0] - ext_x .. coord[0] + ext_x + 1 {
            for y in coord[1] - ext_y .. coord[1] + ext_y + 1 {
                let dist = self.get_distance(coord, [x, y]);
                if dist <= radius {
                    u = fun(u, [x, y]);
                }
            }
        }
        u
    }
}
<|endoftext|>