<commit_before>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This is a regression test for exonum node.
extern crate exonum;
extern crate futures;
extern crate serde_json;
extern crate tokio_timer;

use futures::Future;
use futures::sync::oneshot;
use tokio_timer::Timer;
use serde_json::Value;

use std::thread::{self, JoinHandle};
use std::time::Duration;
use std::sync::{Arc, Mutex};

use exonum::blockchain::{Service, ServiceContext, Transaction};
use exonum::encoding::Error as EncodingError;
use exonum::messages::RawTransaction;
use exonum::node::{ApiSender, ExternalMessage, Node};
use exonum::storage::{Database, Fork, MemoryDB, Snapshot};
use exonum::helpers;
use exonum::crypto::Hash;

struct CommitWatcherService(pub Mutex<Option<oneshot::Sender<()>>>);

impl Service for CommitWatcherService {
    fn service_id(&self) -> u16 {
        255
    }

    fn service_name(&self) -> &str {
        "commit_watcher"
    }

    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        Vec::new()
    }

    fn tx_from_raw(&self, _raw: RawTransaction) -> Result<Box<Transaction>, EncodingError> {
        unreachable!("An unknown transaction received");
    }

    fn handle_commit(&self, _context: &ServiceContext) {
        if let Some(oneshot) = self.0.lock().unwrap().take() {
            oneshot.send(()).unwrap();
        }
    }
}

struct InitializeCheckerService(pub Arc<Mutex<u64>>);

impl Service for InitializeCheckerService {
    fn service_id(&self) -> u16 {
        256
    }

    fn service_name(&self) -> &str {
        "initialize_checker"
    }

    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        Vec::new()
    }

    fn tx_from_raw(&self, _raw: RawTransaction) -> Result<Box<Transaction>, EncodingError> {
        unreachable!("An unknown transaction received");
    }

    fn initialize(&self, _fork: &mut Fork) -> Value {
        *self.0.lock().unwrap() += 1;
        Value::Null
    }
}

struct RunHandle {
    node_thread: JoinHandle<()>,
    api_tx: ApiSender,
}

fn run_nodes(count: u8, start_port: u16) -> (Vec<RunHandle>, Vec<oneshot::Receiver<()>>) {
    let mut node_threads = Vec::new();
    let mut commit_rxs = Vec::new();
    for node_cfg in helpers::generate_testnet_config(count, start_port) {
        let (commit_tx, commit_rx) = oneshot::channel();
        let service = Box::new(CommitWatcherService(Mutex::new(Some(commit_tx))));
        let node = Node::new(MemoryDB::new(), vec![service], node_cfg);
        let api_tx = node.channel();
        node_threads.push(RunHandle {
            node_thread: thread::spawn(move || {
                node.run().unwrap();
            }),
            api_tx,
        });
        commit_rxs.push(commit_rx);
    }
    (node_threads, commit_rxs)
}

#[test]
fn test_node_run() {
    let (nodes, commit_rxs) = run_nodes(4, 16_300);

    let timer = Timer::default();
    let duration = Duration::from_secs(60);
    for rx in commit_rxs {
        let rx = timer.timeout(rx.map_err(drop), duration);
        rx.wait().unwrap();
    }

    for handle in nodes {
        handle
            .api_tx
            .send_external_message(ExternalMessage::Shutdown)
            .unwrap();
        handle.node_thread.join().unwrap();
    }
}

#[test]
fn test_node_shutdown_twice() {
    let (nodes, commit_rxs) = run_nodes(1, 16_400);

    let timer = Timer::default();
    let duration = Duration::from_secs(60);
    for rx in commit_rxs {
        let rx = timer.timeout(rx.map_err(drop), duration);
        rx.wait().unwrap();
    }

    for handle in nodes {
        handle
            .api_tx
            .send_external_message(ExternalMessage::Shutdown)
            .unwrap();
        handle
            .api_tx
            .send_external_message(ExternalMessage::Shutdown)
            .unwrap();
        handle.node_thread.join().unwrap();
    }
}

#[test]
fn test_node_restart_regression() {
    let start_node = |node_cfg, db, init_times| {
        let service = Box::new(InitializeCheckerService(init_times));
        let node = Node::new(db, vec![service], node_cfg);
        let api_tx = node.channel();
        let node_thread = thread::spawn(move || {
            node.run().unwrap();
        });
        // Wait for shutdown
        api_tx
            .send_external_message(ExternalMessage::Shutdown)
            .unwrap();
        node_thread.join().unwrap();
    };

    let db = Arc::from(Box::new(MemoryDB::new()) as Box<Database>) as Arc<Database>;
    let node_cfg = helpers::generate_testnet_config(1, 3600)[0].clone();

    let init_times = Arc::new(Mutex::new(0));
    // First launch
    start_node(node_cfg.clone(), db.clone(), Arc::clone(&init_times));
    // Second launch
    start_node(node_cfg, db, Arc::clone(&init_times));
    assert_eq!(*init_times.lock().unwrap(), 1);
}
<commit_msg>Removed test_node_shutdown_twice (#679) [ECR-1161]<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This is a regression test for exonum node.
extern crate exonum;
extern crate futures;
extern crate serde_json;
extern crate tokio_timer;

use futures::Future;
use futures::sync::oneshot;
use tokio_timer::Timer;
use serde_json::Value;

use std::thread::{self, JoinHandle};
use std::time::Duration;
use std::sync::{Arc, Mutex};

use exonum::blockchain::{Service, ServiceContext, Transaction};
use exonum::encoding::Error as EncodingError;
use exonum::messages::RawTransaction;
use exonum::node::{ApiSender, ExternalMessage, Node};
use exonum::storage::{Database, Fork, MemoryDB, Snapshot};
use exonum::helpers;
use exonum::crypto::Hash;

struct CommitWatcherService(pub Mutex<Option<oneshot::Sender<()>>>);

impl Service for CommitWatcherService {
    fn service_id(&self) -> u16 {
        255
    }

    fn service_name(&self) -> &str {
        "commit_watcher"
    }

    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        Vec::new()
    }

    fn tx_from_raw(&self, _raw: RawTransaction) -> Result<Box<Transaction>, EncodingError> {
        unreachable!("An unknown transaction received");
    }

    fn handle_commit(&self, _context: &ServiceContext) {
        if let Some(oneshot) = self.0.lock().unwrap().take() {
            oneshot.send(()).unwrap();
        }
    }
}

struct InitializeCheckerService(pub Arc<Mutex<u64>>);

impl Service for InitializeCheckerService {
    fn service_id(&self) -> u16 {
        256
    }

    fn service_name(&self) -> &str {
        "initialize_checker"
    }

    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        Vec::new()
    }

    fn tx_from_raw(&self, _raw: RawTransaction) -> Result<Box<Transaction>, EncodingError> {
        unreachable!("An unknown transaction received");
    }

    fn initialize(&self, _fork: &mut Fork) -> Value {
        *self.0.lock().unwrap() += 1;
        Value::Null
    }
}

struct RunHandle {
    node_thread: JoinHandle<()>,
    api_tx: ApiSender,
}

fn run_nodes(count: u8, start_port: u16) -> (Vec<RunHandle>, Vec<oneshot::Receiver<()>>) {
    let mut node_threads = Vec::new();
    let mut commit_rxs = Vec::new();
    for node_cfg in helpers::generate_testnet_config(count, start_port) {
        let (commit_tx, commit_rx) = oneshot::channel();
        let service = Box::new(CommitWatcherService(Mutex::new(Some(commit_tx))));
        let node = Node::new(MemoryDB::new(), vec![service], node_cfg);
        let api_tx = node.channel();
        node_threads.push(RunHandle {
            node_thread: thread::spawn(move || {
                node.run().unwrap();
            }),
            api_tx,
        });
        commit_rxs.push(commit_rx);
    }
    (node_threads, commit_rxs)
}

#[test]
fn test_node_run() {
    let (nodes, commit_rxs) = run_nodes(4, 16_300);

    let timer = Timer::default();
    let duration = Duration::from_secs(60);
    for rx in commit_rxs {
        let rx = timer.timeout(rx.map_err(drop), duration);
        rx.wait().unwrap();
    }

    for handle in nodes {
        handle
            .api_tx
            .send_external_message(ExternalMessage::Shutdown)
            .unwrap();
        handle.node_thread.join().unwrap();
    }
}

#[test]
fn test_node_restart_regression() {
    let start_node = |node_cfg, db, init_times| {
        let service = Box::new(InitializeCheckerService(init_times));
        let node = Node::new(db, vec![service], node_cfg);
        let api_tx = node.channel();
        let node_thread = thread::spawn(move || {
            node.run().unwrap();
        });
        // Wait for shutdown
        api_tx
            .send_external_message(ExternalMessage::Shutdown)
            .unwrap();
        node_thread.join().unwrap();
    };

    let db = Arc::from(Box::new(MemoryDB::new()) as Box<Database>) as Arc<Database>;
    let node_cfg = helpers::generate_testnet_config(1, 3600)[0].clone();

    let init_times = Arc::new(Mutex::new(0));
    // First launch
    start_node(node_cfg.clone(), db.clone(), Arc::clone(&init_times));
    // Second launch
    start_node(node_cfg, db, Arc::clone(&init_times));
    assert_eq!(*init_times.lock().unwrap(), 1);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. 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.

use layers::{ARGB32Format, ContainerLayerKind, Flip, NoFlip, RGB24Format, TextureLayerKind};
use layers::{VerticalFlip};
use layers;
use scene::Scene;
use texturegl::Texture;

use geom::matrix::{Matrix4, ortho};
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, CLAMP_TO_EDGE, COMPILE_STATUS};
use opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, LINEAR, NO_ERROR, RGB, RGBA, BGRA, SCISSOR_BOX};
use opengles::gl2::{SCISSOR_TEST, STATIC_DRAW, TEXTURE_2D, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE0};
use opengles::gl2::{TRIANGLE_STRIP, UNPACK_ALIGNMENT, UNPACK_CLIENT_STORAGE_APPLE};
use opengles::gl2::{UNPACK_ROW_LENGTH, UNSIGNED_BYTE, UNSIGNED_INT_8_8_8_8_REV, VERTEX_SHADER, VIEWPORT};
use opengles::gl2::{GLenum, GLint, GLsizei, GLuint, attach_shader, bind_buffer};
use opengles::gl2::{buffer_data, create_program, clear, clear_color};
use opengles::gl2::{compile_shader, create_shader, draw_arrays, disable, enable, is_enabled};
use opengles::gl2::{enable_vertex_attrib_array, gen_buffers, gen_textures};
use opengles::gl2::{get_attrib_location, get_error, get_integer_v, get_program_iv};
use opengles::gl2::{get_shader_info_log, get_shader_iv, active_texture};
use opengles::gl2::{get_uniform_location, link_program, pixel_store_i, scissor, shader_source};
use opengles::gl2::{tex_image_2d, tex_parameter_i, uniform_1i, uniform_matrix_4fv, use_program};
use opengles::gl2::{vertex_attrib_pointer_f32, viewport};

use std::libc::c_int;
use std::libc::c_uint;

static FRAGMENT_SHADER_SOURCE: &'static str = "
    #ifdef GL_ES
        precision mediump float;
    #endif

    varying vec2 vTextureCoord;

    uniform sampler2D uSampler;

    void main(void) {
        gl_FragColor = texture2D(uSampler, vTextureCoord);
    }
";

static VERTEX_SHADER_SOURCE: &'static str = "
    attribute vec3 aVertexPosition;
    attribute vec2 aTextureCoord;

    uniform mat4 uMVMatrix;
    uniform mat4 uPMatrix;

    varying vec2 vTextureCoord;

    void main(void) {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        vTextureCoord = aTextureCoord;
    }
";

static VERTICES: [f32, ..12] = [
    0.0, 0.0, 0.0,
    0.0, 1.0, 0.0,
    1.0, 0.0, 0.0,
    1.0, 1.0, 0.0,
];

static TEXTURE_COORDINATES: [f32, ..8] = [
    0.0, 0.0,
    0.0, 1.0,
    1.0, 0.0,
    1.0, 1.0,
];

static FLIPPED_TEXTURE_COORDINATES: [f32, ..8] = [
    0.0, 1.0,
    0.0, 0.0,
    1.0, 1.0,
    1.0, 0.0,
];

pub fn load_shader(source_string: &str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, [ source_string.as_bytes().to_owned() ]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!("failed to compile shader");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(fmt!("shader info log: %s", get_shader_info_log(shader_id)));
        fail!("failed to compile shader");
    }

    return shader_id;
}

struct Buffers {
    vertex_buffer: GLuint,
    texture_coordinate_buffer: GLuint,
    flipped_texture_coordinate_buffer: GLuint,
}

pub struct RenderContext {
    program: GLuint,
    vertex_position_attr: c_int,
    texture_coord_attr: c_int,
    modelview_uniform: c_int,
    projection_uniform: c_int,
    sampler_uniform: c_int,
    buffers: Buffers,
}

impl RenderContext {
    fn new(program: GLuint) -> RenderContext {
        let render_context = RenderContext {
            program: program,
            vertex_position_attr: get_attrib_location(program, ~"aVertexPosition"),
            texture_coord_attr: get_attrib_location(program, ~"aTextureCoord"),
            modelview_uniform: get_uniform_location(program, ~"uMVMatrix"),
            projection_uniform: get_uniform_location(program, ~"uPMatrix"),
            sampler_uniform: get_uniform_location(program, ~"uSampler"),
            buffers: RenderContext::init_buffers(),
        };

        enable_vertex_attrib_array(render_context.vertex_position_attr as GLuint);
        enable_vertex_attrib_array(render_context.texture_coord_attr as GLuint);

        render_context
    }

    fn init_buffers() -> Buffers {
        let vertex_buffer = gen_buffers(1)[0];
        bind_buffer(ARRAY_BUFFER, vertex_buffer);
        buffer_data(ARRAY_BUFFER, VERTICES, STATIC_DRAW);

        let texture_coordinate_buffer = gen_buffers(1)[0];
        bind_buffer(ARRAY_BUFFER, texture_coordinate_buffer);
        buffer_data(ARRAY_BUFFER, TEXTURE_COORDINATES, STATIC_DRAW);

        let flipped_texture_coordinate_buffer = gen_buffers(1)[0];
        bind_buffer(ARRAY_BUFFER, flipped_texture_coordinate_buffer);
        buffer_data(ARRAY_BUFFER, FLIPPED_TEXTURE_COORDINATES, STATIC_DRAW);

        Buffers {
            vertex_buffer: vertex_buffer,
            texture_coordinate_buffer: texture_coordinate_buffer,
            flipped_texture_coordinate_buffer: flipped_texture_coordinate_buffer,
        }
    }
}

pub fn init_render_context() -> RenderContext {
    let vertex_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER);
    let fragment_shader = load_shader(FRAGMENT_SHADER_SOURCE, FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!("failed to initialize program");
    }

    use_program(program);
    enable(TEXTURE_2D);

    RenderContext::new(program)
}

pub fn bind_and_render_quad(render_context: RenderContext, texture: &Texture, flip: Flip) {
    active_texture(TEXTURE0);
    let _bound_texture = texture.bind();

    uniform_1i(render_context.sampler_uniform, 0);

    bind_buffer(ARRAY_BUFFER, render_context.buffers.vertex_buffer);
    vertex_attrib_pointer_f32(render_context.vertex_position_attr as GLuint, 3, false, 0, 0);

    match flip {
        NoFlip => bind_buffer(ARRAY_BUFFER, render_context.buffers.texture_coordinate_buffer),
        VerticalFlip => {
            bind_buffer(ARRAY_BUFFER, render_context.buffers.flipped_texture_coordinate_buffer)
        }
    }
    vertex_attrib_pointer_f32(render_context.texture_coord_attr as GLuint, 2, false, 0, 0);

    draw_arrays(TRIANGLE_STRIP, 0, 4);
}

// Layer rendering

pub trait Render {
    fn render(@mut self, render_context: RenderContext, transform: Matrix4<f32>);
}

impl Render for layers::ContainerLayer {
    fn render(@mut self, render_context: RenderContext, transform: Matrix4<f32>) {
        let old_rect_opt = if is_enabled(SCISSOR_TEST) {
            let mut old_rect = [0 as GLint, ..4];
            get_integer_v(SCISSOR_BOX, old_rect);
            Some(Rect(Point2D(old_rect[0], old_rect[1]), Size2D(old_rect[2], old_rect[3])))
        } else {
            None
        };

        match self.scissor {
            Some(rect) => {
                let size = Size2D((rect.size.width * transform.m11) as GLint,
                                  (rect.size.height * transform.m22) as GLint);

                // Get the viewport height so we can flip the origin horizontally
                // since glScissor measures from the bottom left of the viewport
                let mut viewport = [0 as GLint, ..4];
                get_integer_v(VIEWPORT, viewport);
                let w_height = viewport[3];
                let origin = Point2D((rect.origin.x * transform.m11 + transform.m41) as GLint,
                                     w_height
                                     - ((rect.origin.y * transform.m22 + transform.m42) as GLint)
                                     - size.height);
                let rect = Rect(origin, size);

                match old_rect_opt {
                    Some(old_rect) => {
                        // A parent ContainerLayer is already being scissored, so set the
                        // new scissor to the intersection of the two rects.
                        let intersection = rect.intersection(&old_rect);
                        match intersection {
                            Some(new_rect) => {
                                scissor(new_rect.origin.x,
                                        new_rect.origin.y,
                                        new_rect.size.width as GLsizei,
                                        new_rect.size.height as GLsizei);
                                maybe_get_error();
                            }
                            None => {
                                return; // Layer is occluded/offscreen
                            }
                        }
                    }
                    None => {
                        // We are the first ContainerLayer to be scissored.
                        // Check against the viewport to prevent invalid values
                        let w_rect = Rect(Point2D(0 as GLint, 0 as GLint),
                                          Size2D(viewport[2], viewport[3]));
                        let intersection = rect.intersection(&w_rect);
                        match intersection {
                            Some(new_rect) => {
                                enable(SCISSOR_TEST);
                                scissor(new_rect.origin.x,
                                        new_rect.origin.y,
                                        new_rect.size.width as GLsizei,
                                        new_rect.size.height as GLsizei);
                                maybe_get_error();
                            }
                            None => {
                                return; // Layer is offscreen
                            }
                        }
                    }
                }
            }
            None => {} // Nothing to do
        }

        let transform = transform.mul(&self.common.transform);
        for child in self.children() {
            render_layer(render_context, transform, child);
        }

        match (self.scissor, old_rect_opt) {
            (Some(_), Some(old_rect)) => {
                // Set scissor back to the parent's scissoring rect.
                scissor(old_rect.origin.x, old_rect.origin.y,
                        old_rect.size.width as GLsizei,
                        old_rect.size.height as GLsizei);
            }
            (Some(_), None) => {
                // Our parents are not being scissored, so disable scissoring for now
                disable(SCISSOR_TEST);
            }
            (None, _) => {} // Nothing to do
        }
    }
}

impl Render for layers::TextureLayer {
    fn render(@mut self, render_context: RenderContext, transform: Matrix4<f32>) {
        let transform = transform.mul(&self.common.transform);
        uniform_matrix_4fv(render_context.modelview_uniform, false, transform.to_array());
        bind_and_render_quad(render_context, self.texture.get(), self.flip);
    }
}

fn render_layer(render_context: RenderContext, transform: Matrix4<f32>, layer: layers::Layer) {
    match layer {
        ContainerLayerKind(container_layer) => {
            container_layer.render(render_context, transform);
        }
        TextureLayerKind(texture_layer) => {
            texture_layer.render(render_context, transform);
        }
    }
}

pub fn render_scene(render_context: RenderContext, scene: &Scene) {
    // Set the viewport.
    viewport(0 as GLint, 0 as GLint, scene.size.width as GLsizei, scene.size.height as GLsizei);

    // Clear the screen.
    clear_color(0.38f32, 0.36f32, 0.36f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    // Set the projection matrix.
    let projection_matrix = ortho(0.0, scene.size.width, scene.size.height, 0.0, -10.0, 10.0);
    uniform_matrix_4fv(render_context.projection_uniform, false, projection_matrix.to_array());

    // Set up the initial modelview matrix.
    let transform = scene.transform;

    // Render the root layer.
    render_layer(render_context, transform, scene.root);
}

#[cfg(debug)]
fn maybe_get_error() {
    if get_error() != NO_ERROR {
        fail!("GL error: %d", get_error() as int);
    }
}

#[cfg(not(debug))]
fn maybe_get_error() {
    // do nothing
}
<commit_msg>Reverting "Add flipping and modernize the codebase a bit" Revert "Add flipping and modernize the codebase a bit"<commit_after>// Copyright 2013 The Servo Project Developers. 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.

use layers::{ARGB32Format, ContainerLayerKind, Flip, NoFlip, RGB24Format, TextureLayerKind};
use layers::{VerticalFlip};
use layers;
use scene::Scene;
use texturegl::Texture;

use geom::matrix::{Matrix4, ortho};
use geom::point::Point2D;
use geom::size::Size2D;
use geom::rect::Rect;
use opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, CLAMP_TO_EDGE, COMPILE_STATUS};
use opengles::gl2::{FRAGMENT_SHADER, LINK_STATUS, LINEAR, NO_ERROR, RGB, RGBA, BGRA, SCISSOR_BOX};
use opengles::gl2::{SCISSOR_TEST, STATIC_DRAW, TEXTURE_2D, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE0};
use opengles::gl2::{TRIANGLE_STRIP, UNPACK_ALIGNMENT, UNPACK_CLIENT_STORAGE_APPLE};
use opengles::gl2::{UNPACK_ROW_LENGTH, UNSIGNED_BYTE, UNSIGNED_INT_8_8_8_8_REV, VERTEX_SHADER, VIEWPORT};
use opengles::gl2::{GLenum, GLint, GLsizei, GLuint, attach_shader, bind_buffer};
use opengles::gl2::{buffer_data, create_program, clear, clear_color};
use opengles::gl2::{compile_shader, create_shader, draw_arrays, disable, enable, is_enabled};
use opengles::gl2::{enable_vertex_attrib_array, gen_buffers, gen_textures};
use opengles::gl2::{get_attrib_location, get_error, get_integer_v, get_program_iv};
use opengles::gl2::{get_shader_info_log, get_shader_iv, active_texture};
use opengles::gl2::{get_uniform_location, link_program, pixel_store_i, scissor, shader_source};
use opengles::gl2::{tex_image_2d, tex_parameter_i, uniform_1i, uniform_matrix_4fv, use_program};
use opengles::gl2::{vertex_attrib_pointer_f32, viewport};

use std::libc::c_int;
use std::libc::c_uint;

pub fn FRAGMENT_SHADER_SOURCE() -> ~str {
    ~"
        #ifdef GL_ES
            precision mediump float;
        #endif

        varying vec2 vTextureCoord;

        uniform sampler2D uSampler;

        void main(void) {
            gl_FragColor = texture2D(uSampler, vTextureCoord);
        }
    "
}

pub fn VERTEX_SHADER_SOURCE() -> ~str {
    ~"
        attribute vec3 aVertexPosition;
        attribute vec2 aTextureCoord;

        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;

        varying vec2 vTextureCoord;

        void main(void) {
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
            vTextureCoord = aTextureCoord;
        }
    "
}

pub fn load_shader(source_string: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, [ source_string.as_bytes().to_owned() ]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(fmt!("error: %d", get_error() as int));
        fail!(~"failed to compile shader");
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(fmt!("shader info log: %s", get_shader_info_log(shader_id)));
        fail!(~"failed to compile shader");
    }

    return shader_id;
}

pub struct RenderContext {
    program: GLuint,
    vertex_position_attr: c_int,
    texture_coord_attr: c_int,
    modelview_uniform: c_int,
    projection_uniform: c_int,
    sampler_uniform: c_int,
    vertex_buffer: GLuint,
    flipped_vertex_buffer: GLuint,
    texture_coord_buffer: GLuint,
}

pub fn RenderContext(program: GLuint) -> RenderContext {
    let (vertex_buffer, flipped_vertex_buffer, texture_coord_buffer) = init_buffers();
    let rc = RenderContext {
        program: program,
        vertex_position_attr: get_attrib_location(program, ~"aVertexPosition"),
        texture_coord_attr: get_attrib_location(program, ~"aTextureCoord"),
        modelview_uniform: get_uniform_location(program, ~"uMVMatrix"),
        projection_uniform: get_uniform_location(program, ~"uPMatrix"),
        sampler_uniform: get_uniform_location(program, ~"uSampler"),
        vertex_buffer: vertex_buffer,
        flipped_vertex_buffer: flipped_vertex_buffer,
        texture_coord_buffer: texture_coord_buffer,
    };

    enable_vertex_attrib_array(rc.vertex_position_attr as GLuint);
    enable_vertex_attrib_array(rc.texture_coord_attr as GLuint);

    rc
}

pub fn init_render_context() -> RenderContext {
    let vertex_shader = load_shader(VERTEX_SHADER_SOURCE(), VERTEX_SHADER);
    let fragment_shader = load_shader(FRAGMENT_SHADER_SOURCE(), FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail!(~"failed to initialize program");
    }

    use_program(program);
    enable(TEXTURE_2D);

    return RenderContext(program);
}

pub fn init_buffers() -> (GLuint, GLuint, GLuint) {
    let vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, vertex_buffer);
    let vertices: [f32, ..8] = [
        0.0, 0.0,
        0.0, 1.0,
        1.0, 0.0,
        1.0, 1.0,
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);

    let flipped_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, flipped_vertex_buffer);
    let flipped_vertices: [f32, ..8] = [
        0.0, 1.0,
        0.0, 0.0,
        1.0, 1.0,
        1.0, 0.0,
    ];
    buffer_data(ARRAY_BUFFER, flipped_vertices, STATIC_DRAW);

    let texture_coord_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, texture_coord_buffer);

    return (vertex_buffer, flipped_vertex_buffer, texture_coord_buffer);
}

pub fn bind_and_render_quad(render_context: RenderContext, texture: &Texture, flip: Flip) {
    active_texture(TEXTURE0);
    let _bound_texture = texture.bind();

    uniform_1i(render_context.sampler_uniform, 0);

    match flip {
        NoFlip => bind_buffer(ARRAY_BUFFER, render_context.vertex_buffer),
        VerticalFlip => bind_buffer(ARRAY_BUFFER, render_context.flipped_vertex_buffer),
    }

    vertex_attrib_pointer_f32(render_context.vertex_position_attr as GLuint, 3, false, 0, 0);

    // Create the texture coordinate array.
    bind_buffer(ARRAY_BUFFER, render_context.texture_coord_buffer);

    let vertices = [
        0.0f32, 1.0f32,
        0.0f32, 0.0f32,
        1.0f32, 1.0f32,
        1.0f32, 0.0f32,
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);
    vertex_attrib_pointer_f32(render_context.texture_coord_attr as GLuint, 2, false, 0, 0);
    draw_arrays(TRIANGLE_STRIP, 0, 4);
}

// Layer rendering

pub trait Render {
    fn render(@mut self, render_context: RenderContext, transform: Matrix4<f32>);
}

impl Render for layers::ContainerLayer {
    fn render(@mut self, render_context: RenderContext, transform: Matrix4<f32>) {
        let old_rect_opt = if is_enabled(SCISSOR_TEST) {
            let mut old_rect = [0 as GLint, ..4];
            get_integer_v(SCISSOR_BOX, old_rect);
            Some(Rect(Point2D(old_rect[0], old_rect[1]), Size2D(old_rect[2], old_rect[3])))
        } else {
            None
        };

        match self.scissor {
            Some(rect) => {
                let size = Size2D((rect.size.width * transform.m11) as GLint,
                                  (rect.size.height * transform.m22) as GLint);

                // Get the viewport height so we can flip the origin horizontally
                // since glScissor measures from the bottom left of the viewport
                let mut viewport = [0 as GLint, ..4];
                get_integer_v(VIEWPORT, viewport);
                let w_height = viewport[3];
                let origin = Point2D((rect.origin.x * transform.m11 + transform.m41) as GLint,
                                     w_height
                                     - ((rect.origin.y * transform.m22 + transform.m42) as GLint)
                                     - size.height);
                let rect = Rect(origin, size);

                match old_rect_opt {
                    Some(old_rect) => {
                        // A parent ContainerLayer is already being scissored, so set the
                        // new scissor to the intersection of the two rects.
                        let intersection = rect.intersection(&old_rect);
                        match intersection {
                            Some(new_rect) => {
                                scissor(new_rect.origin.x,
                                        new_rect.origin.y,
                                        new_rect.size.width as GLsizei,
                                        new_rect.size.height as GLsizei);
                                maybe_get_error();
                            }
                            None => {
                                return; // Layer is occluded/offscreen
                            }
                        }
                    }
                    None => {
                        // We are the first ContainerLayer to be scissored.
                        // Check against the viewport to prevent invalid values
                        let w_rect = Rect(Point2D(0 as GLint, 0 as GLint),
                                          Size2D(viewport[2], viewport[3]));
                        let intersection = rect.intersection(&w_rect);
                        match intersection {
                            Some(new_rect) => {
                                enable(SCISSOR_TEST);
                                scissor(new_rect.origin.x,
                                        new_rect.origin.y,
                                        new_rect.size.width as GLsizei,
                                        new_rect.size.height as GLsizei);
                                maybe_get_error();
                            }
                            None => {
                                return; // Layer is offscreen
                            }
                        }
                    }
                }
            }
            None => {} // Nothing to do
        }

        let transform = transform.mul(&self.common.transform);
        for child in self.children() {
            render_layer(render_context, transform, child);
        }

        match (self.scissor, old_rect_opt) {
            (Some(_), Some(old_rect)) => {
                // Set scissor back to the parent's scissoring rect.
                scissor(old_rect.origin.x, old_rect.origin.y,
                        old_rect.size.width as GLsizei,
                        old_rect.size.height as GLsizei);
            }
            (Some(_), None) => {
                // Our parents are not being scissored, so disable scissoring for now
                disable(SCISSOR_TEST);
            }
            (None, _) => {} // Nothing to do
        }
    }
}

impl Render for layers::TextureLayer {
    fn render(@mut self, render_context: RenderContext, transform: Matrix4<f32>) {
        let transform = transform.mul(&self.common.transform);
        uniform_matrix_4fv(render_context.modelview_uniform, false, transform.to_array());
        bind_and_render_quad(render_context, self.texture.get(), self.flip);
    }
}

fn render_layer(render_context: RenderContext, transform: Matrix4<f32>, layer: layers::Layer) {
    match layer {
        ContainerLayerKind(container_layer) => {
            container_layer.render(render_context, transform);
        }
        TextureLayerKind(texture_layer) => {
            texture_layer.render(render_context, transform);
        }
    }
}

pub fn render_scene(render_context: RenderContext, scene: &Scene) {
    // Set the viewport.
    viewport(0 as GLint, 0 as GLint, scene.size.width as GLsizei, scene.size.height as GLsizei);

    // Clear the screen.
    clear_color(0.38f32, 0.36f32, 0.36f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    // Set the projection matrix.
    let projection_matrix = ortho(0.0, scene.size.width, scene.size.height, 0.0, -10.0, 10.0);
    uniform_matrix_4fv(render_context.projection_uniform, false, projection_matrix.to_array());

    // Set up the initial modelview matrix.
    let transform = scene.transform;

    // Render the root layer.
    render_layer(render_context, transform, scene.root);
}

#[cfg(debug)]
fn maybe_get_error() {
    if get_error() != NO_ERROR {
        fail!("GL error: %d", get_error() as int);
    }
}

#[cfg(not(debug))]
fn maybe_get_error() {
    // do nothing
}
<|endoftext|>


<commit_before>#![feature(rustc_private, plugin_registrar)]

extern crate syntax;
extern crate rustc;

mod derive_action;

use rustc::plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::SyntaxExtension;

use derive_action::expand_derive_action_annotation;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(intern("derive_Action"),
                                       SyntaxExtension::MultiDecorator(
                                           Box::new(expand_derive_action_annotation)));
}<commit_msg>Reorder `extern crate` declarations to be alphabetical<commit_after>#![feature(rustc_private, plugin_registrar)]

extern crate rustc;
extern crate syntax;

mod derive_action;

use rustc::plugin::Registry;
use syntax::parse::token::intern;
use syntax::ext::base::SyntaxExtension;

use derive_action::expand_derive_action_annotation;

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(intern("derive_Action"),
                                       SyntaxExtension::MultiDecorator(
                                           Box::new(expand_derive_action_annotation)));
}<|endoftext|>


<commit_before>//! Implements building a CMake-based C++ library.

use crate::cpp_build_config::{CppBuildConfigData, CppBuildPaths, CppLibraryType};
use crate::errors::{err_msg, Result};
use crate::file_utils::{create_dir_all, file_to_string, path_to_str};
use crate::target;
use crate::utils::{run_command, run_command_and_capture_output, CommandOutput, MapIfOk};
use itertools::Itertools;
use log::debug;
use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::Command;

/// A CMake variable with a name and a value.
#[derive(Debug, Clone)]
pub struct CMakeVar {
    pub name: String,
    pub value: String,
}
impl CMakeVar {
    /// Creates a new variable.
    pub fn new<S1: Into<String>, S2: Into<String>>(name: S1, value: S2) -> Self {
        CMakeVar {
            name: name.into(),
            value: value.into(),
        }
    }
    /// Creates a new variable containing a list of values.
    pub fn new_list<I, S, L>(name: S, values: L) -> Result<Self>
    where
        S: Display + Into<String>,
        I: AsRef<str> + Display,
        L: IntoIterator<Item = I>,
    {
        let value = values
            .into_iter()
            .map_if_ok(|s| -> Result<_> {
                if s.as_ref().contains(';') {
                    Err(err_msg(format!(
                        "can't pass value to cmake because ';' symbol is reserved: {}",
                        s.as_ref()
                    )))
                } else {
                    Ok(s)
                }
            })?
            .into_iter()
            .join(";");
        Ok(CMakeVar::new(name, value))
    }

    /// Creates a new variable containing a list of paths.
    pub fn new_path_list<I, S, L>(name: S, paths: L) -> Result<CMakeVar>
    where
        S: Into<String> + Display,
        I: AsRef<Path>,
        L: IntoIterator<Item = I>,
    {
        CMakeVar::new_list(
            name,
            paths
                .into_iter()
                .map_if_ok(|x| path_to_str(x.as_ref()).map(|x| x.to_string()))?,
        )
    }
}

/// CMake build type (Debug or Release)
#[derive(Debug, Clone)]
pub enum BuildType {
    Debug,
    Release,
}

/// Implements building a CMake-based C++ library.
/// Construct a value and call `run()` to execute building.
#[derive(Debug, Clone)]
pub struct CppLibBuilder {
    /// Path to the source directory containing CMake config file
    pub cmake_source_dir: PathBuf,
    /// Path to the build directory (may not exist before building)
    pub build_dir: PathBuf,
    /// Path to the install directory (may not exist before building)
    pub install_dir: Option<PathBuf>,
    /// Number of threads used to build the library. If `None` is supplied,
    /// number of threads will be detected automatically.
    pub num_jobs: Option<usize>,
    /// CMake build type (Debug or Release)
    pub build_type: BuildType,
    /// Additional variables passed to CMake
    pub cmake_vars: Vec<CMakeVar>,
    pub capture_output: bool,
    pub skip_cmake: bool,
    pub skip_cmake_after_first_run: bool,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CppLibBuilderOutput {
    Success,
    Fail(CommandOutput),
}

impl CppLibBuilderOutput {
    pub fn is_success(&self) -> bool {
        self == &CppLibBuilderOutput::Success
    }
}

impl CppLibBuilder {
    /// Builds the library.
    pub fn run(&mut self) -> Result<CppLibBuilderOutput> {
        if !self.build_dir.exists() {
            create_dir_all(&self.build_dir)?;
        }
        if !self.skip_cmake {
            let mut cmake_command = Command::new("cmake");
            cmake_command
                .arg(&self.cmake_source_dir)
                .current_dir(&self.build_dir);
            let actual_build_type = if target::current_env() == target::Env::Msvc {
                // Rust always links to release version of MSVC runtime, so
                // link will fail if C library is built in debug mode
                BuildType::Release
            } else {
                self.build_type.clone()
            };
            if target::current_os() == target::OS::Windows {
                match target::current_env() {
                    target::Env::Msvc => {
                        cmake_command.arg("-G").arg("NMake Makefiles");
                    }
                    target::Env::Gnu => {
                        cmake_command.arg("-G").arg("MinGW Makefiles");
                    }
                    _ => {}
                }
            }
            let mut actual_cmake_vars = self.cmake_vars.clone();
            actual_cmake_vars.push(CMakeVar::new(
                "CMAKE_BUILD_TYPE",
                match actual_build_type {
                    BuildType::Release => "Release",
                    BuildType::Debug => "Debug",
                },
            ));
            if let Some(install_dir) = &self.install_dir {
                actual_cmake_vars.push(CMakeVar::new(
                    "CMAKE_INSTALL_PREFIX",
                    path_to_str(install_dir)?,
                ));
            }

            for var in actual_cmake_vars {
                cmake_command.arg(format!("-D{}={}", var.name, var.value));
            }
            if self.capture_output {
                let output = run_command_and_capture_output(&mut cmake_command)?;
                if !output.is_success() {
                    return Ok(CppLibBuilderOutput::Fail(output));
                }
            } else {
                run_command(&mut cmake_command)?;
            }
        }

        if self.skip_cmake_after_first_run {
            self.skip_cmake = true;
        }

        let mut make_command_name = if target::current_os() == target::OS::Windows {
            match target::current_env() {
                target::Env::Msvc => "nmake",
                target::Env::Gnu => "mingw32-make",
                _ => "make",
            }
        } else {
            "make"
        };

        if target::current_env() == target::Env::Msvc && self.capture_output {
            let path = self.build_dir.join("nmake_output.txt");
            run_command(
                Command::new("cmd")
                    .arg("/C")
                    .arg(format!(
                        "{} clean > {} 2>&1",
                        make_command_name,
                        path_to_str(&path)?
                    ))
                    .current_dir(&self.build_dir),
            )?;
        } else {
            run_command(
                Command::new(&make_command_name)
                    .arg("clean")
                    .current_dir(&self.build_dir),
            )?;
        }

        let mut make_args = Vec::new();
        let num_jobs = if let Some(x) = self.num_jobs {
            x
        } else {
            ::num_cpus::get()
        };
        if target::current_env() == target::Env::Msvc && num_jobs > 1 {
            debug!("Checking for jom");
            if run_command(&mut Command::new("jom").arg("/version")).is_ok() {
                debug!("jom will be used instead of nmake.");
                make_command_name = "jom";
                make_args.push("/J".to_string());
                make_args.push(num_jobs.to_string());
            } else {
                debug!("jom not found in PATH. Using nmake.");
            }
        }
        if target::current_env() != target::Env::Msvc {
            make_args.push(format!("-j{}", num_jobs));
        }
        if self.install_dir.is_some() {
            make_args.push("install".to_string());
        }

        let mut capture_output_file = None;
        let mut make_command = if target::current_env() == target::Env::Msvc && self.capture_output
        {
            let path = self.build_dir.join("nmake_output.txt");
            let mut make_command = Command::new("cmd");
            make_command.arg("/C").arg(format!(
                "{} {} > {} 2>&1",
                make_command_name,
                make_args.join(" "),
                path_to_str(&path)?
            ));
            capture_output_file = Some(path);
            make_command
        } else {
            let mut make_command = Command::new(make_command_name);
            make_command.args(&make_args);
            make_command
        };

        make_command.current_dir(&self.build_dir);
        if self.capture_output {
            if let Some(capture_output_file) = capture_output_file {
                if let Err(err) = run_command(&mut make_command) {
                    let output = CommandOutput {
                        status: unsafe { std::mem::zeroed() },
                        stderr: format!(
                            "{}\n{}",
                            err.to_string(),
                            file_to_string(capture_output_file)?
                        ),
                        stdout: String::new(),
                    };
                    return Ok(CppLibBuilderOutput::Fail(output));
                }
            } else {
                let output = run_command_and_capture_output(&mut make_command)?;
                if !output.is_success() {
                    return Ok(CppLibBuilderOutput::Fail(output));
                }
            }
        } else {
            run_command(&mut make_command)?;
        }
        Ok(CppLibBuilderOutput::Success)
    }
}

pub struct CMakeConfigData<'a, 'b> {
    pub cpp_build_config_data: &'a CppBuildConfigData,
    pub cpp_build_paths: &'b CppBuildPaths,
    pub library_type: Option<CppLibraryType>,
    pub cpp_library_version: Option<String>,
}

pub fn version_to_number(version: &str) -> Result<u32> {
    const COEF: u64 = 100;
    let parsed = semver::Version::parse(version)?;
    let value = parsed.major * COEF * COEF + parsed.minor * COEF + parsed.patch;
    Ok(value as u32)
}

impl<'a, 'b> CMakeConfigData<'a, 'b> {
    pub fn cmake_vars(&self) -> Result<Vec<CMakeVar>> {
        let mut cmake_vars = Vec::new();
        if let Some(library_type) = self.library_type {
            cmake_vars.push(CMakeVar::new(
                "RITUAL_LIBRARY_TYPE",
                match library_type {
                    CppLibraryType::Shared => "SHARED",
                    CppLibraryType::Static => "STATIC",
                },
            ));
        }
        if let Some(version) = &self.cpp_library_version {
            cmake_vars.push(CMakeVar::new(
                "RITUAL_CPP_LIB_VERSION",
                version_to_number(version)?.to_string(),
            ));
        }
        cmake_vars.push(CMakeVar::new_path_list(
            "RITUAL_INCLUDE_PATH",
            self.cpp_build_paths.include_paths(),
        )?);
        cmake_vars.push(CMakeVar::new_path_list(
            "RITUAL_LIBRARY_PATH",
            self.cpp_build_paths.lib_paths(),
        )?);
        cmake_vars.push(CMakeVar::new_path_list(
            "RITUAL_FRAMEWORK_PATH",
            self.cpp_build_paths.framework_paths(),
        )?);
        cmake_vars.push(CMakeVar::new_list(
            "RITUAL_LINKED_LIBS",
            self.cpp_build_config_data.linked_libs(),
        )?);
        cmake_vars.push(CMakeVar::new_list(
            "RITUAL_LINKED_FRAMEWORKS",
            self.cpp_build_config_data.linked_frameworks(),
        )?);
        cmake_vars.push(CMakeVar::new(
            "RITUAL_COMPILER_FLAGS",
            self.cpp_build_config_data.compiler_flags().join(" "),
        ));
        Ok(cmake_vars)
    }
}
<commit_msg>use cmake for building instead of make<commit_after>//! Implements building a CMake-based C++ library.

use crate::cpp_build_config::{CppBuildConfigData, CppBuildPaths, CppLibraryType};
use crate::errors::{err_msg, Result};
use crate::file_utils::{create_dir_all, file_to_string, path_to_str};
use crate::target;
use crate::utils::{run_command, run_command_and_capture_output, CommandOutput, MapIfOk};
use itertools::Itertools;
use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::Command;

/// A CMake variable with a name and a value.
#[derive(Debug, Clone)]
pub struct CMakeVar {
    pub name: String,
    pub value: String,
}
impl CMakeVar {
    /// Creates a new variable.
    pub fn new<S1: Into<String>, S2: Into<String>>(name: S1, value: S2) -> Self {
        CMakeVar {
            name: name.into(),
            value: value.into(),
        }
    }
    /// Creates a new variable containing a list of values.
    pub fn new_list<I, S, L>(name: S, values: L) -> Result<Self>
    where
        S: Display + Into<String>,
        I: AsRef<str> + Display,
        L: IntoIterator<Item = I>,
    {
        let value = values
            .into_iter()
            .map_if_ok(|s| -> Result<_> {
                if s.as_ref().contains(';') {
                    Err(err_msg(format!(
                        "can't pass value to cmake because ';' symbol is reserved: {}",
                        s.as_ref()
                    )))
                } else {
                    Ok(s)
                }
            })?
            .into_iter()
            .join(";");
        Ok(CMakeVar::new(name, value))
    }

    /// Creates a new variable containing a list of paths.
    pub fn new_path_list<I, S, L>(name: S, paths: L) -> Result<CMakeVar>
    where
        S: Into<String> + Display,
        I: AsRef<Path>,
        L: IntoIterator<Item = I>,
    {
        CMakeVar::new_list(
            name,
            paths
                .into_iter()
                .map_if_ok(|x| path_to_str(x.as_ref()).map(|x| x.to_string()))?,
        )
    }
}

/// CMake build type (Debug or Release)
#[derive(Debug, Clone)]
pub enum BuildType {
    Debug,
    Release,
}

/// Implements building a CMake-based C++ library.
/// Construct a value and call `run()` to execute building.
#[derive(Debug, Clone)]
pub struct CppLibBuilder {
    /// Path to the source directory containing CMake config file
    pub cmake_source_dir: PathBuf,
    /// Path to the build directory (may not exist before building)
    pub build_dir: PathBuf,
    /// Path to the install directory (may not exist before building)
    pub install_dir: Option<PathBuf>,
    /// Number of threads used to build the library. If `None` is supplied,
    /// number of threads will be detected automatically.
    pub num_jobs: Option<usize>,
    /// CMake build type (Debug or Release)
    pub build_type: BuildType,
    /// Additional variables passed to CMake
    pub cmake_vars: Vec<CMakeVar>,
    pub capture_output: bool,
    pub skip_cmake: bool,
    pub skip_cmake_after_first_run: bool,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CppLibBuilderOutput {
    Success,
    Fail(CommandOutput),
}

impl CppLibBuilderOutput {
    pub fn is_success(&self) -> bool {
        self == &CppLibBuilderOutput::Success
    }
}

impl CppLibBuilder {
    /// Builds the library.
    pub fn run(&mut self) -> Result<CppLibBuilderOutput> {
        if !self.build_dir.exists() {
            create_dir_all(&self.build_dir)?;
        }
        if !self.skip_cmake {
            let mut cmake_command = Command::new("cmake");
            cmake_command
                .arg(&self.cmake_source_dir)
                .current_dir(&self.build_dir);
            let actual_build_type = if target::current_env() == target::Env::Msvc {
                // Rust always links to release version of MSVC runtime, so
                // link will fail if C library is built in debug mode
                BuildType::Release
            } else {
                self.build_type.clone()
            };
            if target::current_os() == target::OS::Windows {
                match target::current_env() {
                    target::Env::Msvc => {
                        cmake_command.arg("-G").arg("NMake Makefiles");
                    }
                    target::Env::Gnu => {
                        cmake_command.arg("-G").arg("MinGW Makefiles");
                    }
                    _ => {}
                }
            }
            let mut actual_cmake_vars = self.cmake_vars.clone();
            actual_cmake_vars.push(CMakeVar::new(
                "CMAKE_BUILD_TYPE",
                match actual_build_type {
                    BuildType::Release => "Release",
                    BuildType::Debug => "Debug",
                },
            ));
            if let Some(install_dir) = &self.install_dir {
                actual_cmake_vars.push(CMakeVar::new(
                    "CMAKE_INSTALL_PREFIX",
                    path_to_str(install_dir)?,
                ));
            }

            for var in actual_cmake_vars {
                cmake_command.arg(format!("-D{}={}", var.name, var.value));
            }
            if self.capture_output {
                let output = run_command_and_capture_output(&mut cmake_command)?;
                if !output.is_success() {
                    return Ok(CppLibBuilderOutput::Fail(output));
                }
            } else {
                run_command(&mut cmake_command)?;
            }
        }

        if self.skip_cmake_after_first_run {
            self.skip_cmake = true;
        }

        if target::current_env() == target::Env::Msvc && self.capture_output {
            let path = self.build_dir.join("nmake_output.txt");
            run_command(
                Command::new("cmd")
                    .arg("/C")
                    .arg(format!(
                        "cmake --build . -- clean > {} 2>&1",
                        path_to_str(&path)?
                    ))
                    .current_dir(&self.build_dir),
            )?;
        } else {
            run_command(
                Command::new("cmake")
                    .arg("--build")
                    .arg(".")
                    .arg("--")
                    .arg("clean")
                    .current_dir(&self.build_dir),
            )?;
        }

        let mut make_args = vec!["--build".to_string(), ".".to_string(), "--".to_string()];
        let num_jobs = if let Some(x) = self.num_jobs {
            x
        } else {
            ::num_cpus::get()
        };

        if target::current_env() != target::Env::Msvc {
            make_args.push(format!("-j{}", num_jobs));
        }
        if self.install_dir.is_some() {
            make_args.push("install".to_string());
        }

        let mut capture_output_file = None;
        let mut make_command = if target::current_env() == target::Env::Msvc && self.capture_output
        {
            let path = self.build_dir.join("nmake_output.txt");
            let mut make_command = Command::new("cmd");
            make_command.arg("/C").arg(format!(
                "cmake {} > {} 2>&1",
                make_args.join(" "),
                path_to_str(&path)?
            ));
            capture_output_file = Some(path);
            make_command
        } else {
            let mut make_command = Command::new("cmake");
            make_command.args(&make_args);
            make_command
        };

        make_command.current_dir(&self.build_dir);
        if self.capture_output {
            if let Some(capture_output_file) = capture_output_file {
                if let Err(err) = run_command(&mut make_command) {
                    let output = CommandOutput {
                        status: unsafe { std::mem::zeroed() },
                        stderr: format!(
                            "{}\n{}",
                            err.to_string(),
                            file_to_string(capture_output_file)?
                        ),
                        stdout: String::new(),
                    };
                    return Ok(CppLibBuilderOutput::Fail(output));
                }
            } else {
                let output = run_command_and_capture_output(&mut make_command)?;
                if !output.is_success() {
                    return Ok(CppLibBuilderOutput::Fail(output));
                }
            }
        } else {
            run_command(&mut make_command)?;
        }
        Ok(CppLibBuilderOutput::Success)
    }
}

pub struct CMakeConfigData<'a, 'b> {
    pub cpp_build_config_data: &'a CppBuildConfigData,
    pub cpp_build_paths: &'b CppBuildPaths,
    pub library_type: Option<CppLibraryType>,
    pub cpp_library_version: Option<String>,
}

pub fn version_to_number(version: &str) -> Result<u32> {
    const COEF: u64 = 100;
    let parsed = semver::Version::parse(version)?;
    let value = parsed.major * COEF * COEF + parsed.minor * COEF + parsed.patch;
    Ok(value as u32)
}

impl<'a, 'b> CMakeConfigData<'a, 'b> {
    pub fn cmake_vars(&self) -> Result<Vec<CMakeVar>> {
        let mut cmake_vars = Vec::new();
        if let Some(library_type) = self.library_type {
            cmake_vars.push(CMakeVar::new(
                "RITUAL_LIBRARY_TYPE",
                match library_type {
                    CppLibraryType::Shared => "SHARED",
                    CppLibraryType::Static => "STATIC",
                },
            ));
        }
        if let Some(version) = &self.cpp_library_version {
            cmake_vars.push(CMakeVar::new(
                "RITUAL_CPP_LIB_VERSION",
                version_to_number(version)?.to_string(),
            ));
        }
        cmake_vars.push(CMakeVar::new_path_list(
            "RITUAL_INCLUDE_PATH",
            self.cpp_build_paths.include_paths(),
        )?);
        cmake_vars.push(CMakeVar::new_path_list(
            "RITUAL_LIBRARY_PATH",
            self.cpp_build_paths.lib_paths(),
        )?);
        cmake_vars.push(CMakeVar::new_path_list(
            "RITUAL_FRAMEWORK_PATH",
            self.cpp_build_paths.framework_paths(),
        )?);
        cmake_vars.push(CMakeVar::new_list(
            "RITUAL_LINKED_LIBS",
            self.cpp_build_config_data.linked_libs(),
        )?);
        cmake_vars.push(CMakeVar::new_list(
            "RITUAL_LINKED_FRAMEWORKS",
            self.cpp_build_config_data.linked_frameworks(),
        )?);
        cmake_vars.push(CMakeVar::new(
            "RITUAL_COMPILER_FLAGS",
            self.cpp_build_config_data.compiler_flags().join(" "),
        ));
        Ok(cmake_vars)
    }
}
<|endoftext|>


<commit_before>//! Finds the appropriate `protoc` binary and Protobuf include directory for this host, and outputs
//! build directives so that the main `prost-build` crate can use them.
//!
//! The following locations are checked for `protoc` in decreasing priority:
//!
//!     1. The `PROTOC` environment variable.
//!     2. The bundled `protoc`.
//!     3. The `protoc` on the `PATH`.
//!
//! If no `protoc` binary is available in these locations, the build fails.
//!
//! The following locations are checked for the Protobuf include directory in decreasing priority:
//!
//!     1. The `PROTOC_INCLUDE` environment variable.
//!     2. The bundled Protobuf include directory.

use std::env;
use std::path::PathBuf;

/// Returns the path to the location of the bundled Protobuf artifacts.
fn bundle_path() -> PathBuf {
    env::current_dir()
        .unwrap()
        .join("third-party")
        .join("protobuf")
}

/// Returns the path to the `protoc` pointed to by the `PROTOC` environment variable, if it is set.
fn env_protoc() -> Option<PathBuf> {
    let protoc = match env::var_os("PROTOC") {
        Some(path) => PathBuf::from(path),
        None => return None,
    };

    if !protoc.exists() {
        panic!(
            "PROTOC environment variable points to non-existent file ({:?})",
            protoc
        );
    }

    Some(protoc)
}

/// Returns the path to the bundled `protoc`, if it is available for the host platform.
fn bundled_protoc() -> Option<PathBuf> {
    let protoc_bin_name = match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86") => "protoc-linux-x86_32",
        ("linux", "x86_64") => "protoc-linux-x86_64",
        ("linux", "aarch64") => "protoc-linux-aarch_64",
        ("macos", "x86_64") => "protoc-osx-x86_64",
        ("windows", _) => "protoc-win32.exe",
        _ => return None,
    };

    Some(bundle_path().join(protoc_bin_name))
}

/// Returns the path to the `protoc` included on the `PATH`, if it exists.
fn path_protoc() -> Option<PathBuf> {
    which::which("protoc").ok()
}

/// Returns the path to the Protobuf include directory pointed to by the `PROTOC_INCLUDE`
/// environment variable, if it is set.
fn env_protoc_include() -> Option<PathBuf> {
    let protoc_include = match env::var_os("PROTOC_INCLUDE") {
        Some(path) => PathBuf::from(path),
        None => return None,
    };

    if !protoc_include.exists() {
        panic!(
            "PROTOC_INCLUDE environment variable points to non-existent directory ({:?})",
            protoc_include
        );
    }
    if !protoc_include.is_dir() {
        panic!(
            "PROTOC_INCLUDE environment variable points to a non-directory file ({:?})",
            protoc_include
        );
    }

    Some(protoc_include)
}

/// Returns the path to the bundled Protobuf include directory.
fn bundled_protoc_include() -> PathBuf {
    bundle_path().join("include")
}

fn main() {
    let protoc = env_protoc()
        .or_else(bundled_protoc)
        .or_else(path_protoc)
        .expect(
            "Failed to find the protoc binary. The PROTOC environment variable is not set, \
             there is no bundled protoc for this platform, and protoc is not in the PATH",
        );

    let protoc_include = env_protoc_include().unwrap_or_else(bundled_protoc_include);

    println!("cargo:rustc-env=PROTOC={}", protoc.display());
    println!(
        "cargo:rustc-env=PROTOC_INCLUDE={}",
        protoc_include.display()
    );
    println!("cargo:rerun-if-env-changed=PROTOC");
    println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE");
}
<commit_msg>Remove the check for existing protoc at build time (#283)<commit_after>//! Finds the appropriate `protoc` binary and Protobuf include directory for this host, and outputs
//! build directives so that the main `prost-build` crate can use them.
//!
//! The following locations are checked for `protoc` in decreasing priority:
//!
//!     1. The `PROTOC` environment variable.
//!     2. The bundled `protoc`.
//!     3. The `protoc` on the `PATH`.
//!
//! If no `protoc` binary is available in these locations, the build fails.
//!
//! The following locations are checked for the Protobuf include directory in decreasing priority:
//!
//!     1. The `PROTOC_INCLUDE` environment variable.
//!     2. The bundled Protobuf include directory.

use std::env;
use std::path::PathBuf;

/// Returns the path to the location of the bundled Protobuf artifacts.
fn bundle_path() -> PathBuf {
    env::current_dir()
        .unwrap()
        .join("third-party")
        .join("protobuf")
}

/// Returns the path to the `protoc` pointed to by the `PROTOC` environment variable, if it is set.
fn env_protoc() -> Option<PathBuf> {
    let protoc = match env::var_os("PROTOC") {
        Some(path) => PathBuf::from(path),
        None => return None,
    };

    Some(protoc)
}

/// Returns the path to the bundled `protoc`, if it is available for the host platform.
fn bundled_protoc() -> Option<PathBuf> {
    let protoc_bin_name = match (env::consts::OS, env::consts::ARCH) {
        ("linux", "x86") => "protoc-linux-x86_32",
        ("linux", "x86_64") => "protoc-linux-x86_64",
        ("linux", "aarch64") => "protoc-linux-aarch_64",
        ("macos", "x86_64") => "protoc-osx-x86_64",
        ("windows", _) => "protoc-win32.exe",
        _ => return None,
    };

    Some(bundle_path().join(protoc_bin_name))
}

/// Returns the path to the `protoc` included on the `PATH`, if it exists.
fn path_protoc() -> Option<PathBuf> {
    which::which("protoc").ok()
}

/// Returns the path to the Protobuf include directory pointed to by the `PROTOC_INCLUDE`
/// environment variable, if it is set.
fn env_protoc_include() -> Option<PathBuf> {
    let protoc_include = match env::var_os("PROTOC_INCLUDE") {
        Some(path) => PathBuf::from(path),
        None => return None,
    };

    if !protoc_include.exists() {
        panic!(
            "PROTOC_INCLUDE environment variable points to non-existent directory ({:?})",
            protoc_include
        );
    }
    if !protoc_include.is_dir() {
        panic!(
            "PROTOC_INCLUDE environment variable points to a non-directory file ({:?})",
            protoc_include
        );
    }

    Some(protoc_include)
}

/// Returns the path to the bundled Protobuf include directory.
fn bundled_protoc_include() -> PathBuf {
    bundle_path().join("include")
}

fn main() {
    let protoc = env_protoc()
        .or_else(bundled_protoc)
        .or_else(path_protoc)
        .expect(
            "Failed to find the protoc binary. The PROTOC environment variable is not set, \
             there is no bundled protoc for this platform, and protoc is not in the PATH",
        );

    let protoc_include = env_protoc_include().unwrap_or_else(bundled_protoc_include);

    println!("cargo:rustc-env=PROTOC={}", protoc.display());
    println!(
        "cargo:rustc-env=PROTOC_INCLUDE={}",
        protoc_include.display()
    );
    println!("cargo:rerun-if-env-changed=PROTOC");
    println!("cargo:rerun-if-env-changed=PROTOC_INCLUDE");
}
<|endoftext|>


<commit_before>use card_strategy::CardStrategy;

use card::Card;
use card::Suit;
use card::Rank;
use deal::Deal;
use game_status::GameStatus;
use game_status::RoundParameters;
use game_status::GameParticipant;
use player::PlayerName;

use std::collections::BTreeMap;
use std::collections::BTreeSet;

#[derive(Debug)]
pub struct DefensiveCardStrategy;

impl DefensiveCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus) -> (i32, i32, i32, i32) {
        let remaining_cards = game_status.unplayed_cards();

        let potential_points = Self::potential_points(card, &game_status.game_players, &game_status.in_progress_deal, &remaining_cards, &game_status.round_parameters);
        let definite_points = if Self::will_win_deal(card, &game_status.game_players, &game_status.in_progress_deal, &remaining_cards) {
            potential_points
        } else {
            0
        };
        let later_potential_points = 0 - Self::later_potential_points(card, &remaining_cards, &game_status.round_parameters);
        let rank_modifier = if game_status.round_parameters.points(card) < 0 {
            -1
        } else {
            1
        };
        let card_rank =  0 - (u32::from(card.rank) as i32) * rank_modifier;
        (definite_points, potential_points, later_potential_points, card_rank)
    }

    fn can_win_deal(card: &Card, in_progress_deal: &Option<Deal>) -> bool {
        in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == suit)
                    .max()
                    .map(|winning_card| card.suit == suit && card.rank > winning_card.rank))).unwrap_or(true)
    }

    fn will_win_deal(card: &Card, game_players: &Vec<GameParticipant>, in_progress_deal: &Option<Deal>, remaining_cards: &BTreeSet<Card>) -> bool {
        Self::can_win_deal(card, in_progress_deal) && (Self::plays_left(game_players, in_progress_deal).len() == 0 || {
            let suit = Self::deal_suit(in_progress_deal).unwrap_or(&card.suit);
            remaining_cards.iter()
                .filter(|other| &other.suit == suit)
                .max()
                .map(|winning_card| card.rank > winning_card.rank).unwrap_or(true)
        })
    }

    fn deal_suit(in_progress_deal: &Option<Deal>) -> Option<&Suit> {
        in_progress_deal.as_ref().and_then(|deal| deal.suit.as_ref())
    }

    fn plays_left<'a>(game_players: &'a Vec<GameParticipant>, in_progress_deal: &Option<Deal>) -> BTreeSet<&'a PlayerName> {
        let mut players: BTreeSet<&PlayerName> = game_players.iter()
            .filter(|player| !player.has_turn)
            .map(|player| &player.team_name)
            .collect();

        if let &Some(ref deal) = in_progress_deal {
            for deal_card in &deal.deal_cards {
                players.remove(&deal_card.player_name);
            }
        }

        players
    }

    fn dealt_cards(in_progress_deal: &Option<Deal>) -> BTreeSet<&Card> {
        in_progress_deal.as_ref()
            .map(|deal| deal.deal_cards.iter().map(|deal_card| &deal_card.card).collect())
            .unwrap_or_default()
    }

    fn potential_points(card: &Card, game_players: &Vec<GameParticipant>, in_progress_deal: &Option<Deal>, remaining_cards: &BTreeSet<Card>, round_parameters: &RoundParameters) -> i32 {
        if Self::can_win_deal(card, in_progress_deal) {
            let dealt_cards = Self::dealt_cards(in_progress_deal);

            let card_points = round_parameters.points(card);

            let dealt_points: i32 = dealt_cards.iter()
                .map(|other| round_parameters.points(other))
                .sum();

            let suit_points: i32 = remaining_cards.iter()
                .filter(|other| other.suit == card.suit)
                .filter(|other| other.rank < card.rank)
                .map(|other| round_parameters.points(other))
                .sum();

            let other_points: i32 = remaining_cards.iter()
                .filter(|other| other.suit != card.suit)
                .map(|other| round_parameters.points(other))
                .filter(|points| points > &0)
                .sum();

            let number_of_suit = remaining_cards.iter().filter(|other| other.suit == card.suit).map(|_| 1).sum::<u32>();
            let number_dealt = dealt_cards.len() as u32;

            let safe_target = 10 - number_dealt;

            let suit_win_points = if number_dealt < 3 {
                (Self::chance_of_win(card, game_players, in_progress_deal, remaining_cards) * (suit_points as f32)) as i32
            } else {
                0
            };

            let other_win_points = if number_of_suit < safe_target && number_dealt < 3 {
                (Self::chance_of_later_win(card, remaining_cards) * (other_points as f32)) as i32
            } else {
                0
            };

            card_points + dealt_points + suit_win_points + other_win_points
        } else {
            0
        }
    }

    fn later_potential_points(card: &Card, remaining_cards: &BTreeSet<Card>, round_parameters: &RoundParameters) -> i32 {
        let card_points = round_parameters.points(card);

        let suit_points: i32 = remaining_cards.iter()
            .filter(|other| other.suit == card.suit)
            .filter(|other| other.rank < card.rank)
            .map(|other| round_parameters.points(other))
            .sum();

        let other_points: i32 = remaining_cards.iter()
            .filter(|other| other.suit != card.suit)
            .map(|other| round_parameters.points(other))
            .filter(|points| points > &0)
            .sum();

        let other_win_points = (Self::chance_of_later_win(card, remaining_cards) * (other_points as f32)) as i32;

        card_points + suit_points + other_win_points
    }

    fn chance_of_later_win(card: &Card, remaining_cards: &BTreeSet<Card>) -> f32 {
        let suit_cards = remaining_cards.iter().filter(|other| other.suit == card.suit).collect::<Vec<_>>();
        let will_win_count = suit_cards.iter().filter(|other| other.rank < card.rank).collect::<Vec<_>>().len();
        if suit_cards.is_empty() {
            1.0
        } else {
            (will_win_count as f32) / (suit_cards.len() as f32)
        }
    }

    fn chance_of_win(card: &Card, game_players: &Vec<GameParticipant>, in_progress_deal: &Option<Deal>, remaining_cards: &BTreeSet<Card>) -> f32 {
        if Self::will_win_deal(card, game_players, in_progress_deal, remaining_cards) {
            1.0
        } else {
            if Self::deal_suit(in_progress_deal).map(|suit| suit == &card.suit).unwrap_or(true) && Self::plays_left(game_players, in_progress_deal).len() > 0 {
                let suit_cards = remaining_cards.iter().filter(|other| other.suit == card.suit).collect::<Vec<_>>();
                let will_win_count = suit_cards.iter().filter(|other| other.rank < card.rank).collect::<Vec<_>>().len();
                if suit_cards.is_empty() {
                    1.0
                } else {
                    (will_win_count as f32) / (suit_cards.len() as f32)
                }
            } else {
                0.0
            }
        }
    }

    fn pass_card<'a>(hand: &'a BTreeSet<Card>, remaining_cards: &BTreeSet<Card>, round_parameters: &RoundParameters) -> Option<&'a Card> {
        hand.iter()
            .filter(|card| !remaining_cards.contains(card))
            .map(|card| ((0 - Self::later_potential_points(card, &remaining_cards, round_parameters), card), card))
            .collect::<BTreeMap<_, &Card>>()
            .into_iter()
            .map(|kv| kv.1)
            .next()
    }

}

impl CardStrategy for DefensiveCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        let mut remaining_cards = game_status.unplayed_cards();

        let card1 = Self::pass_card(&game_status.my_initial_hand, &remaining_cards, &game_status.round_parameters);
        if let Some(card) = card1 { remaining_cards.insert(card.clone()); };
        let card2 = Self::pass_card(&game_status.my_initial_hand, &remaining_cards, &game_status.round_parameters);
        if let Some(card) = card2 { remaining_cards.insert(card.clone()); };
        let card3 = Self::pass_card(&game_status.my_initial_hand, &remaining_cards, &game_status.round_parameters);

        vec!(card1, card2, card3).into_iter().filter_map(|card| card).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let two_of_clubs = Rank::Two.of(Suit::Club);
        if let Some(card) = game_status.my_current_hand.iter().find(|&card| card == &two_of_clubs) {
            card
        } else {
            let current_suit = game_status.in_progress_deal.as_ref().and_then(|deal| deal.suit);
            let mut valid_cards = game_status.my_current_hand.iter()
                .filter(|card| Some(card.suit) == current_suit)
                .collect::<Vec<&Card>>();

            if valid_cards.is_empty() {
                valid_cards.extend(&game_status.my_current_hand);
            }

            let evaluation = valid_cards.into_iter()
                .map(|card| ((Self::score_card(card, game_status), card), card))
                .collect::<BTreeMap<_,&Card>>();

            println!("Remaining: {}", game_status.unplayed_cards().iter().map(|card| format!("{}", card)).collect::<Vec<_>>().join(", "));
            for item in &evaluation {
                println!("{}: {:?}", item.1, (item.0).0);
            }

            evaluation.values()
                .next()
                .expect("No valid cards to play!")
        }
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use player::PlayerName;
    use card::Card;
    use card::Rank::*;
    use card::Suit::*;
    use game_status::GameStatus;
    use game_status::dto::GameStatusDto;
    use card_strategy::CardStrategy;

    use try_from::TryFrom;
    use error::Error;

    extern crate serde;
    extern crate serde_json;

    use std::fs::File;
    use std::io::Read;

    fn open_scenario(name: &str) -> GameStatus {
        let file_name = format!("samples/scenarios/{}.json", name.replace("_", " "));
        let mut game_status_file = File::open(file_name).unwrap();
        let mut game_status_string = String::new();
        game_status_file.read_to_string(&mut game_status_string).unwrap();
        let game_status_dto: GameStatusDto = serde_json::from_str(&game_status_string).map_err(Error::from).unwrap();
        GameStatus::try_from(game_status_dto).unwrap()
    }

    fn should_play(name: &str, expected_card: Card) {
        let player_name = PlayerName::new("Derek Williams");
        let game_status = open_scenario(name);
        let card = DefensiveCardStrategy.play_card(&game_status, &player_name).clone();
        assert_eq!(expected_card, card);
    }

    macro_rules! test_play {
        ($($name:ident => $card:expr)*) => {
            $(#[test]
            fn $name() {
                should_play(stringify!($name), $card);
            })*
        }
    }

    test_play! {
        normal_1 => Jack.of(Diamond)
        normal_2 => King.of(Club)
        normal_3 => Six.of(Spade)

        should_play_heart_1 => Seven.of(Heart)
        should_play_heart_2 => Four.of(Heart)
        should_not_play_high_heart_1 => Six.of(Spade)
        should_play_high_rank_1 => King.of(Diamond)
        should_play_high_rank_2 => Ace.of(Spade)
        should_play_high_rank_3 => Ace.of(Spade)
        should_not_crash_during_card_play => Ten.of(Heart)
        // should_play_low_negative_points_card_1 => Two.of(Diamond)
        should_play_high_negative_points_card_1 => Ace.of(Diamond)
        should_try_to_win_deal_1 => Queen.of(Club)

        // corrections to this game cause no difference to outcome
        normal_game_1_01_01 => Four.of(Club)
        normal_game_1_01_02 => Eight.of(Heart)
        normal_game_1_01_03 => Seven.of(Club) // Six.of(Club)
        normal_game_1_01_04 => Five.of(Spade)
        normal_game_1_01_05 => Ten.of(Club) // Seven.of(Club)
        normal_game_1_01_06 => Seven.of(Heart)
        normal_game_1_01_07 => Six.of(Heart)
        normal_game_1_01_08 => Four.of(Diamond)
        normal_game_1_01_09 => Ten.of(Club)
        normal_game_1_01_10 => Nine.of(Club)
        normal_game_1_01_11 => Three.of(Heart)
        normal_game_1_01_12 => Four.of(Spade)
        normal_game_1_01_13 => Two.of(Spade)

        // corrections to this game cause no difference to outcome
        normal_game_1_02_01 => Eight.of(Club) // Six of Club
        normal_game_1_02_02 => Queen.of(Diamond)
        normal_game_1_02_03 => Eight.of(Club)
        normal_game_1_02_04 => Ace.of(Heart)
        normal_game_1_02_05 => Three.of(Heart)
        normal_game_1_02_06 => Eight.of(Diamond)
        normal_game_1_02_07 => Five.of(Diamond)
        normal_game_1_02_08 => Nine.of(Spade)
        normal_game_1_02_09 => Eight.of(Spade)
        normal_game_1_02_10 => Seven.of(Spade)
        normal_game_1_02_11 => Six.of(Spade)
        normal_game_1_02_12 => Three.of(Spade)
        normal_game_1_02_13 => Two.of(Spade)
    }

}<commit_msg>fix deal winning logic when playing first card<commit_after>use card_strategy::CardStrategy;

use card::Card;
use card::Suit;
use card::Rank;
use deal::Deal;
use game_status::GameStatus;
use game_status::RoundParameters;
use game_status::GameParticipant;
use player::PlayerName;

use std::collections::BTreeMap;
use std::collections::BTreeSet;

#[derive(Debug)]
pub struct DefensiveCardStrategy;

impl DefensiveCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus) -> (i32, i32, i32, i32) {
        let remaining_cards = game_status.unplayed_cards();

        let potential_points = Self::potential_points(card, &game_status.game_players, &game_status.in_progress_deal, &remaining_cards, &game_status.round_parameters);
        let definite_points = if Self::will_win_deal(card, &game_status.game_players, &game_status.in_progress_deal, &remaining_cards) {
            potential_points
        } else {
            0
        };
        let later_potential_points = 0 - Self::later_potential_points(card, &remaining_cards, &game_status.round_parameters);
        let rank_modifier = if game_status.round_parameters.points(card) < 0 {
            -1
        } else {
            1
        };
        let card_rank =  0 - (u32::from(card.rank) as i32) * rank_modifier;
        (definite_points, potential_points, later_potential_points, card_rank)
    }

    fn can_win_deal(card: &Card, in_progress_deal: &Option<Deal>) -> bool {
        in_progress_deal.as_ref().and_then(|deal| {
            let suit = &deal.suit.unwrap_or(card.suit);
            deal.deal_cards.iter()
                .map(|deal_card| deal_card.card)
                .filter(|other| &other.suit == suit)
                .max()
                .map(|winning_card| &card.suit == suit && card.rank > winning_card.rank)
        }).unwrap_or(true)
    }

    fn will_win_deal(card: &Card, game_players: &Vec<GameParticipant>, in_progress_deal: &Option<Deal>, remaining_cards: &BTreeSet<Card>) -> bool {
        Self::can_win_deal(card, in_progress_deal) && (Self::plays_left(game_players, in_progress_deal).len() == 0 || {
            let suit = Self::deal_suit(in_progress_deal).unwrap_or(&card.suit);
            remaining_cards.iter()
                .filter(|other| &other.suit == suit)
                .max()
                .map(|winning_card| card.rank > winning_card.rank).unwrap_or(true)
        })
    }

    fn deal_suit(in_progress_deal: &Option<Deal>) -> Option<&Suit> {
        in_progress_deal.as_ref().and_then(|deal| deal.suit.as_ref())
    }

    fn plays_left<'a>(game_players: &'a Vec<GameParticipant>, in_progress_deal: &Option<Deal>) -> BTreeSet<&'a PlayerName> {
        let mut players: BTreeSet<&PlayerName> = game_players.iter()
            .filter(|player| !player.has_turn)
            .map(|player| &player.team_name)
            .collect();

        if let &Some(ref deal) = in_progress_deal {
            for deal_card in &deal.deal_cards {
                players.remove(&deal_card.player_name);
            }
        }

        players
    }

    fn dealt_cards(in_progress_deal: &Option<Deal>) -> BTreeSet<&Card> {
        in_progress_deal.as_ref()
            .map(|deal| deal.deal_cards.iter().map(|deal_card| &deal_card.card).collect())
            .unwrap_or_default()
    }

    fn potential_points(card: &Card, game_players: &Vec<GameParticipant>, in_progress_deal: &Option<Deal>, remaining_cards: &BTreeSet<Card>, round_parameters: &RoundParameters) -> i32 {
        if Self::can_win_deal(card, in_progress_deal) {
            let dealt_cards = Self::dealt_cards(in_progress_deal);

            let card_points = round_parameters.points(card);

            let dealt_points: i32 = dealt_cards.iter()
                .map(|other| round_parameters.points(other))
                .sum();

            let suit_points: i32 = remaining_cards.iter()
                .filter(|other| other.suit == card.suit)
                .filter(|other| other.rank < card.rank)
                .map(|other| round_parameters.points(other))
                .sum();

            let other_points: i32 = remaining_cards.iter()
                .filter(|other| other.suit != card.suit)
                .map(|other| round_parameters.points(other))
                .filter(|points| points > &0)
                .sum();

            let number_of_suit = remaining_cards.iter().filter(|other| other.suit == card.suit).map(|_| 1).sum::<u32>();
            let number_dealt = dealt_cards.len() as u32;

            let safe_target = 10 - number_dealt;

            let suit_win_points = if number_dealt < 3 {
                (Self::chance_of_win(card, game_players, in_progress_deal, remaining_cards) * (suit_points as f32)) as i32
            } else {
                0
            };

            let other_win_points = if number_of_suit < safe_target && number_dealt < 3 {
                (Self::chance_of_later_win(card, remaining_cards) * (other_points as f32)) as i32
            } else {
                0
            };

            card_points + dealt_points + suit_win_points + other_win_points
        } else {
            0
        }
    }

    fn later_potential_points(card: &Card, remaining_cards: &BTreeSet<Card>, round_parameters: &RoundParameters) -> i32 {
        let card_points = round_parameters.points(card);

        let suit_points: i32 = remaining_cards.iter()
            .filter(|other| other.suit == card.suit)
            .filter(|other| other.rank < card.rank)
            .map(|other| round_parameters.points(other))
            .sum();

        let other_points: i32 = remaining_cards.iter()
            .filter(|other| other.suit != card.suit)
            .map(|other| round_parameters.points(other))
            .filter(|points| points > &0)
            .sum();

        let other_win_points = (Self::chance_of_later_win(card, remaining_cards) * (other_points as f32)) as i32;

        card_points + suit_points + other_win_points
    }

    fn chance_of_later_win(card: &Card, remaining_cards: &BTreeSet<Card>) -> f32 {
        let suit_cards = remaining_cards.iter().filter(|other| other.suit == card.suit).collect::<Vec<_>>();
        let will_win_count = suit_cards.iter().filter(|other| other.rank < card.rank).collect::<Vec<_>>().len();
        if suit_cards.is_empty() {
            1.0
        } else {
            (will_win_count as f32) / (suit_cards.len() as f32)
        }
    }

    fn chance_of_win(card: &Card, game_players: &Vec<GameParticipant>, in_progress_deal: &Option<Deal>, remaining_cards: &BTreeSet<Card>) -> f32 {
        if Self::will_win_deal(card, game_players, in_progress_deal, remaining_cards) {
            1.0
        } else {
            if Self::deal_suit(in_progress_deal).map(|suit| suit == &card.suit).unwrap_or(true) && Self::plays_left(game_players, in_progress_deal).len() > 0 {
                let suit_cards = remaining_cards.iter().filter(|other| other.suit == card.suit).collect::<Vec<_>>();
                let will_win_count = suit_cards.iter().filter(|other| other.rank < card.rank).collect::<Vec<_>>().len();
                if suit_cards.is_empty() {
                    1.0
                } else {
                    (will_win_count as f32) / (suit_cards.len() as f32)
                }
            } else {
                0.0
            }
        }
    }

    fn pass_card<'a>(hand: &'a BTreeSet<Card>, remaining_cards: &BTreeSet<Card>, round_parameters: &RoundParameters) -> Option<&'a Card> {
        hand.iter()
            .filter(|card| !remaining_cards.contains(card))
            .map(|card| ((0 - Self::later_potential_points(card, &remaining_cards, round_parameters), card), card))
            .collect::<BTreeMap<_, &Card>>()
            .into_iter()
            .map(|kv| kv.1)
            .next()
    }

}

impl CardStrategy for DefensiveCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        let mut remaining_cards = game_status.unplayed_cards();

        let card1 = Self::pass_card(&game_status.my_initial_hand, &remaining_cards, &game_status.round_parameters);
        if let Some(card) = card1 { remaining_cards.insert(card.clone()); };
        let card2 = Self::pass_card(&game_status.my_initial_hand, &remaining_cards, &game_status.round_parameters);
        if let Some(card) = card2 { remaining_cards.insert(card.clone()); };
        let card3 = Self::pass_card(&game_status.my_initial_hand, &remaining_cards, &game_status.round_parameters);

        vec!(card1, card2, card3).into_iter().filter_map(|card| card).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let two_of_clubs = Rank::Two.of(Suit::Club);
        if let Some(card) = game_status.my_current_hand.iter().find(|&card| card == &two_of_clubs) {
            card
        } else {
            let current_suit = game_status.in_progress_deal.as_ref().and_then(|deal| deal.suit);
            let mut valid_cards = game_status.my_current_hand.iter()
                .filter(|card| Some(card.suit) == current_suit)
                .collect::<Vec<&Card>>();

            if valid_cards.is_empty() {
                valid_cards.extend(&game_status.my_current_hand);
            }

            let evaluation = valid_cards.into_iter()
                .map(|card| ((Self::score_card(card, game_status), card), card))
                .collect::<BTreeMap<_,&Card>>();

            println!("Remaining: {}", game_status.unplayed_cards().iter().map(|card| format!("{}", card)).collect::<Vec<_>>().join(", "));
            for item in &evaluation {
                println!("{}: {:?}", item.1, (item.0).0);
            }

            evaluation.values()
                .next()
                .expect("No valid cards to play!")
        }
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use player::PlayerName;
    use card::Card;
    use card::Rank::*;
    use card::Suit::*;
    use game_status::GameStatus;
    use game_status::dto::GameStatusDto;
    use card_strategy::CardStrategy;

    use try_from::TryFrom;
    use error::Error;

    extern crate serde;
    extern crate serde_json;

    use std::fs::File;
    use std::io::Read;

    fn open_scenario(name: &str) -> GameStatus {
        let file_name = format!("samples/scenarios/{}.json", name.replace("_", " "));
        let mut game_status_file = File::open(file_name).unwrap();
        let mut game_status_string = String::new();
        game_status_file.read_to_string(&mut game_status_string).unwrap();
        let game_status_dto: GameStatusDto = serde_json::from_str(&game_status_string).map_err(Error::from).unwrap();
        GameStatus::try_from(game_status_dto).unwrap()
    }

    fn should_play(name: &str, expected_card: Card) {
        let player_name = PlayerName::new("Derek Williams");
        let game_status = open_scenario(name);
        let card = DefensiveCardStrategy.play_card(&game_status, &player_name).clone();
        assert_eq!(expected_card, card);
    }

    macro_rules! test_play {
        ($($name:ident => $card:expr)*) => {
            $(#[test]
            fn $name() {
                should_play(stringify!($name), $card);
            })*
        }
    }

    test_play! {
        normal_1 => Jack.of(Diamond)
        normal_2 => King.of(Club)
        normal_3 => Six.of(Spade)

        should_play_heart_1 => Seven.of(Heart)
        should_play_heart_2 => Four.of(Heart)
        should_not_play_high_heart_1 => Six.of(Spade)
        should_play_high_rank_1 => King.of(Diamond)
        should_play_high_rank_2 => Ace.of(Spade)
        should_play_high_rank_3 => Ace.of(Spade)
        should_not_crash_during_card_play => Ten.of(Heart)
        // should_play_low_negative_points_card_1 => Two.of(Diamond)
        should_play_high_negative_points_card_1 => Ace.of(Diamond)
        should_try_to_win_deal_1 => Queen.of(Club)

        // corrections to this game cause no difference to outcome
        normal_game_1_01_01 => Four.of(Club)
        normal_game_1_01_02 => Eight.of(Heart)
        normal_game_1_01_03 => Seven.of(Club) // Six.of(Club)
        normal_game_1_01_04 => Five.of(Spade)
        normal_game_1_01_05 => Ten.of(Club) // Seven.of(Club)
        normal_game_1_01_06 => Seven.of(Heart)
        normal_game_1_01_07 => Six.of(Heart)
        normal_game_1_01_08 => Four.of(Diamond)
        normal_game_1_01_09 => Ten.of(Club)
        normal_game_1_01_10 => Nine.of(Club)
        normal_game_1_01_11 => Three.of(Heart)
        normal_game_1_01_12 => Four.of(Spade)
        normal_game_1_01_13 => Two.of(Spade)

        // corrections to this game cause no difference to outcome
        normal_game_1_02_01 => Eight.of(Club) // Six of Club
        normal_game_1_02_02 => Queen.of(Diamond)
        normal_game_1_02_03 => Eight.of(Club)
        normal_game_1_02_04 => Ace.of(Heart)
        normal_game_1_02_05 => Three.of(Heart)
        normal_game_1_02_06 => Eight.of(Diamond)
        normal_game_1_02_07 => Five.of(Diamond)
        normal_game_1_02_08 => Nine.of(Spade)
        normal_game_1_02_09 => Eight.of(Spade)
        normal_game_1_02_10 => Seven.of(Spade)
        normal_game_1_02_11 => Six.of(Spade)
        normal_game_1_02_12 => Three.of(Spade)
        normal_game_1_02_13 => Two.of(Spade)
    }

}<|endoftext|>


<commit_before>use std::ptr;
use std;

use ll::*;
use wchar;
use instance::Instance;

pub trait ToHandle {
    fn to_handle(&self) -> HANDLE;
}

impl<T: ToHandle> ToHandle for Option<T> {
    fn to_handle(&self) -> HANDLE {
        match *self {
            None => ptr::mut_null(),
            Some(ref s) => s.to_handle(),
        }
    }
}

pub enum ImageType {
    IMAGE_BITMAP = 0,
    IMAGE_CURSOR = 1,
    IMAGE_ICON = 2,
}

pub struct Image {
    image: HANDLE,
}

impl Image {
    #[fixed_stack_segment]
    pub fn load_resource(instance: Instance, id: int, img_type: ImageType, width: int, height: int) -> Option<Image> {
        let img = unsafe {
            LoadImageW(
                instance.instance, std::cast::transmute(id), img_type as UINT,
                width as c_int, height as c_int, 0x8000
            )
        };

        if img == ptr::mut_null() {
            None
        } else {
            Some(Image { image: img })
        }
    }

    pub fn load_cursor_resource(id: int) -> Option<Image> {
        let null_instance = Instance { instance: ptr::mut_null() };
        Image::load_resource(null_instance, id, IMAGE_CURSOR, 0, 0)
    }
}

impl ToHandle for Image {
    fn to_handle(&self) -> HANDLE {
        self.image
    }
}

pub enum MenuResource {
    MenuName(~str),
    MenuId(int),
}

impl MenuResource {
    pub fn with_menu_p<T>(&self, f: &fn(*u16) -> T) -> T {
        match *self {
            MenuName(ref s) => wchar::with_utf16_p(*s, f),
            MenuId(id) => unsafe { f(std::cast::transmute(id)) },
        }
    }

    pub fn null() -> MenuResource {
        MenuId(0)
    }
}
<commit_msg>Fix ImageType values<commit_after>use std::ptr;
use std;

use ll::*;
use wchar;
use instance::Instance;

pub trait ToHandle {
    fn to_handle(&self) -> HANDLE;
}

impl<T: ToHandle> ToHandle for Option<T> {
    fn to_handle(&self) -> HANDLE {
        match *self {
            None => ptr::mut_null(),
            Some(ref s) => s.to_handle(),
        }
    }
}

pub enum ImageType {
    IMAGE_BITMAP = 0,
    IMAGE_ICON = 1,
    IMAGE_CURSOR = 2,
}

pub struct Image {
    image: HANDLE,
}

impl Image {
    #[fixed_stack_segment]
    pub fn load_resource(instance: Instance, id: int, img_type: ImageType, width: int, height: int) -> Option<Image> {
        let img = unsafe {
            LoadImageW(
                instance.instance, std::cast::transmute(id), img_type as UINT,
                width as c_int, height as c_int, 0x8000
            )
        };

        if img == ptr::mut_null() {
            None
        } else {
            Some(Image { image: img })
        }
    }

    pub fn load_cursor_resource(id: int) -> Option<Image> {
        let null_instance = Instance { instance: ptr::mut_null() };
        Image::load_resource(null_instance, id, IMAGE_CURSOR, 0, 0)
    }
}

impl ToHandle for Image {
    fn to_handle(&self) -> HANDLE {
        self.image
    }
}

pub enum MenuResource {
    MenuName(~str),
    MenuId(int),
}

impl MenuResource {
    pub fn with_menu_p<T>(&self, f: &fn(*u16) -> T) -> T {
        match *self {
            MenuName(ref s) => wchar::with_utf16_p(*s, f),
            MenuId(id) => unsafe { f(std::cast::transmute(id)) },
        }
    }

    pub fn null() -> MenuResource {
        MenuId(0)
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate scribe;

use test::Bencher;
use scribe::Workspace;
use std::path::PathBuf;

#[bench]
fn bench_tokens(b: &mut Bencher) {
    // Create a workspace with this benchmark test as a buffer.
    let mut workspace = Workspace::new(PathBuf::from("."));
    let path = PathBuf::from("benches/buffer_tokens.rs");
    workspace.open_buffer(path);

    // Benchmark the buffer's tokens method.
    let buffer = workspace.current_buffer().unwrap();
    b.iter(|| buffer.tokens());
}
<commit_msg>Update tokens benchmark to exhaust iterator<commit_after>#![feature(test)]

extern crate test;
extern crate scribe;

use test::Bencher;
use scribe::Workspace;
use std::path::PathBuf;

#[bench]
fn bench_tokens(b: &mut Bencher) {
    // Create a workspace with this benchmark test as a buffer.
    let mut workspace = Workspace::new(PathBuf::from("."));
    let path = PathBuf::from("benches/buffer_tokens.rs");
    workspace.open_buffer(path);

    // Benchmark the buffer's tokens method.
    let buffer = workspace.current_buffer().unwrap();
    b.iter(|| {
        let mut tokens = buffer.tokens().unwrap();

        // Exhaust the token iterator.
        for _ in tokens.iter() {}
    });
}
<|endoftext|>