<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gleam::gl;
use std::mem;
use std::rc::Rc;

use device::FrameId;

pub trait NamedTag {
    fn get_label(&self) -> &str;
}

#[derive(Debug, Clone)]
pub struct GpuTimer<T> {
    pub tag: T,
    pub time_ns: u64,
}

#[derive(Debug, Clone)]
pub struct GpuSampler<T> {
    pub tag: T,
    pub count: u64,
}

pub struct QuerySet<T> {
    set: Vec<gl::GLuint>,
    data: Vec<T>,
    pending: gl::GLuint,
}

impl<T> QuerySet<T> {
    fn new() -> Self {
        QuerySet {
            set: Vec::new(),
            data: Vec::new(),
            pending: 0,
        }
    }

    fn reset(&mut self) {
        self.data.clear();
        self.pending = 0;
    }

    fn add(&mut self, value: T) -> Option<gl::GLuint> {
        assert_eq!(self.pending, 0);
        self.set.get(self.data.len()).cloned().map(|query_id| {
            self.data.push(value);
            self.pending = query_id;
            query_id
        })
    }

    fn take<F: Fn(&mut T, gl::GLuint)>(&mut self, fun: F) -> Vec<T> {
        let mut data = mem::replace(&mut self.data, Vec::new());
        for (value, &query) in data.iter_mut().zip(self.set.iter()) {
            fun(value, query)
        }
        data
    }
}

pub struct GpuFrameProfile<T> {
    gl: Rc<gl::Gl>,
    timers: QuerySet<GpuTimer<T>>,
    samplers: QuerySet<GpuSampler<T>>,
    frame_id: FrameId,
    inside_frame: bool,
}

impl<T> GpuFrameProfile<T> {
    fn new(gl: Rc<gl::Gl>) -> Self {
        assert_eq!(gl.get_type(), gl::GlType::Gl);

        GpuFrameProfile {
            gl,
            timers: QuerySet::new(),
            samplers: QuerySet::new(),
            frame_id: FrameId::new(0),
            inside_frame: false,
        }
    }

    fn enable_timers(&mut self, count: i32) {
        self.timers.set = self.gl.gen_queries(count);
    }

    fn disable_timers(&mut self) {
        if !self.timers.set.is_empty() {
            self.gl.delete_queries(&self.timers.set);
        }
        self.timers.set = Vec::new();
    }

    fn enable_samplers(&mut self, count: i32) {
        self.samplers.set = self.gl.gen_queries(count);
    }

    fn disable_samplers(&mut self) {
        if !self.samplers.set.is_empty() {
            self.gl.delete_queries(&self.samplers.set);
        }
        self.samplers.set = Vec::new();
    }

    fn begin_frame(&mut self, frame_id: FrameId) {
        self.frame_id = frame_id;
        self.timers.reset();
        self.samplers.reset();
        self.inside_frame = true;
    }

    fn end_frame(&mut self) {
        self.finish_timer();
        self.finish_sampler();
        self.inside_frame = false;
    }

    fn finish_timer(&mut self) {
        debug_assert!(self.inside_frame);
        if self.timers.pending != 0 {
            self.gl.end_query(gl::TIME_ELAPSED);
            self.timers.pending = 0;
        }
    }

    fn finish_sampler(&mut self) {
        debug_assert!(self.inside_frame);
        if self.samplers.pending != 0 {
            self.gl.end_query(gl::SAMPLES_PASSED);
            self.samplers.pending = 0;
        }
    }
}

impl<T: NamedTag> GpuFrameProfile<T> {
    fn start_timer(&mut self, tag: T) -> GpuTimeQuery {
        self.finish_timer();

        let marker = GpuMarker::new(&self.gl, tag.get_label());

        if let Some(query) = self.timers.add(GpuTimer { tag, time_ns: 0 }) {
            self.gl.begin_query(gl::TIME_ELAPSED, query);
        }

        GpuTimeQuery(marker)
    }

    fn start_sampler(&mut self, tag: T) -> GpuSampleQuery {
        self.finish_sampler();

        if let Some(query) = self.samplers.add(GpuSampler { tag, count: 0 }) {
            self.gl.begin_query(gl::SAMPLES_PASSED, query);
        }

        GpuSampleQuery
    }

    fn build_samples(&mut self) -> (FrameId, Vec<GpuTimer<T>>, Vec<GpuSampler<T>>) {
        debug_assert!(!self.inside_frame);
        let gl = &self.gl;

        (
            self.frame_id,
            self.timers.take(|timer, query| {
                timer.time_ns = gl.get_query_object_ui64v(query, gl::QUERY_RESULT)
            }),
            self.samplers.take(|sampler, query| {
                sampler.count = gl.get_query_object_ui64v(query, gl::QUERY_RESULT)
            }),
        )
    }
}

impl<T> Drop for GpuFrameProfile<T> {
    fn drop(&mut self) {
        self.disable_timers();
        self.disable_samplers();
    }
}

pub struct GpuProfiler<T> {
    gl: Rc<gl::Gl>,
    frames: Vec<GpuFrameProfile<T>>,
    next_frame: usize,
}

impl<T> GpuProfiler<T> {
    pub fn new(gl: Rc<gl::Gl>) -> Self {
        const MAX_PROFILE_FRAMES: usize = 4;
        let frames = (0 .. MAX_PROFILE_FRAMES)
            .map(|_| GpuFrameProfile::new(Rc::clone(&gl)))
            .collect();

        GpuProfiler {
            gl,
            next_frame: 0,
            frames,
        }
    }

    pub fn enable_timers(&mut self) {
        const MAX_TIMERS_PER_FRAME: i32 = 256;

        for frame in &mut self.frames {
            frame.enable_timers(MAX_TIMERS_PER_FRAME);
        }
    }

    pub fn disable_timers(&mut self) {
        for frame in &mut self.frames {
            frame.disable_timers();
        }
    }

    pub fn toggle_timers_enabled(&mut self) {
        if self.frames[0].timers.set.is_empty() {
            self.enable_timers();
        } else {
            self.disable_timers();
        }
    }

    pub fn enable_samplers(&mut self) {
        const MAX_SAMPLERS_PER_FRAME: i32 = 16;
        if cfg!(target_os = "macos") {
            warn!("Expect OSX driver bugs related to sample queries")
        }

        for frame in &mut self.frames {
            frame.enable_samplers(MAX_SAMPLERS_PER_FRAME);
        }
    }

    pub fn disable_samplers(&mut self) {
        for frame in &mut self.frames {
            frame.disable_samplers();
        }
    }

    pub fn toggle_samplers_enabled(&mut self) {
        if self.frames[0].samplers.set.is_empty() {
            self.enable_samplers();
        } else {
            self.disable_samplers();
        }
    }
}

impl<T: NamedTag> GpuProfiler<T> {
    pub fn build_samples(&mut self) -> (FrameId, Vec<GpuTimer<T>>, Vec<GpuSampler<T>>) {
        self.frames[self.next_frame].build_samples()
    }

    pub fn begin_frame(&mut self, frame_id: FrameId) {
        self.frames[self.next_frame].begin_frame(frame_id);
    }

    pub fn end_frame(&mut self) {
        self.frames[self.next_frame].end_frame();
        self.next_frame = (self.next_frame + 1) % self.frames.len();
    }

    pub fn start_timer(&mut self, tag: T) -> GpuTimeQuery {
        self.frames[self.next_frame].start_timer(tag)
    }

    pub fn start_sampler(&mut self, tag: T) -> GpuSampleQuery {
        self.frames[self.next_frame].start_sampler(tag)
    }

    pub fn finish_sampler(&mut self, _sampler: GpuSampleQuery) {
        self.frames[self.next_frame].finish_sampler()
    }

    pub fn start_marker(&mut self, label: &str) -> GpuMarker {
        GpuMarker::new(&self.gl, label)
    }

    pub fn place_marker(&mut self, label: &str) {
        GpuMarker::fire(&self.gl, label)
    }
}

#[must_use]
pub struct GpuMarker {
    gl: Option<Rc<gl::Gl>>,
}

impl GpuMarker {
    fn new(gl: &Rc<gl::Gl>, message: &str) -> Self {
        if gl.get_type() == gl::GlType::Gl {
            gl.push_group_marker_ext(message);
            GpuMarker { gl: Some(Rc::clone(gl)) }
        } else {
            GpuMarker { gl: None }
        }
    }

    fn fire(gl: &Rc<gl::Gl>, message: &str) {
        if gl.get_type() == gl::GlType::Gl {
            gl.insert_event_marker_ext(message);
        }
    }
}

impl Drop for GpuMarker {
    fn drop(&mut self) {
        if let Some(ref gl) = self.gl {
            gl.pop_group_marker_ext();
        }
    }
}

#[must_use]
pub struct GpuTimeQuery(GpuMarker);
#[must_use]
pub struct GpuSampleQuery;
<commit_msg>Query GL assertion removal<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use gleam::gl;
use std::mem;
use std::rc::Rc;

use device::FrameId;

pub trait NamedTag {
    fn get_label(&self) -> &str;
}

#[derive(Debug, Clone)]
pub struct GpuTimer<T> {
    pub tag: T,
    pub time_ns: u64,
}

#[derive(Debug, Clone)]
pub struct GpuSampler<T> {
    pub tag: T,
    pub count: u64,
}

pub struct QuerySet<T> {
    set: Vec<gl::GLuint>,
    data: Vec<T>,
    pending: gl::GLuint,
}

impl<T> QuerySet<T> {
    fn new() -> Self {
        QuerySet {
            set: Vec::new(),
            data: Vec::new(),
            pending: 0,
        }
    }

    fn reset(&mut self) {
        self.data.clear();
        self.pending = 0;
    }

    fn add(&mut self, value: T) -> Option<gl::GLuint> {
        assert_eq!(self.pending, 0);
        self.set.get(self.data.len()).cloned().map(|query_id| {
            self.data.push(value);
            self.pending = query_id;
            query_id
        })
    }

    fn take<F: Fn(&mut T, gl::GLuint)>(&mut self, fun: F) -> Vec<T> {
        let mut data = mem::replace(&mut self.data, Vec::new());
        for (value, &query) in data.iter_mut().zip(self.set.iter()) {
            fun(value, query)
        }
        data
    }
}

pub struct GpuFrameProfile<T> {
    gl: Rc<gl::Gl>,
    timers: QuerySet<GpuTimer<T>>,
    samplers: QuerySet<GpuSampler<T>>,
    frame_id: FrameId,
    inside_frame: bool,
}

impl<T> GpuFrameProfile<T> {
    fn new(gl: Rc<gl::Gl>) -> Self {
        GpuFrameProfile {
            gl,
            timers: QuerySet::new(),
            samplers: QuerySet::new(),
            frame_id: FrameId::new(0),
            inside_frame: false,
        }
    }

    fn enable_timers(&mut self, count: i32) {
        self.timers.set = self.gl.gen_queries(count);
    }

    fn disable_timers(&mut self) {
        if !self.timers.set.is_empty() {
            self.gl.delete_queries(&self.timers.set);
        }
        self.timers.set = Vec::new();
    }

    fn enable_samplers(&mut self, count: i32) {
        self.samplers.set = self.gl.gen_queries(count);
    }

    fn disable_samplers(&mut self) {
        if !self.samplers.set.is_empty() {
            self.gl.delete_queries(&self.samplers.set);
        }
        self.samplers.set = Vec::new();
    }

    fn begin_frame(&mut self, frame_id: FrameId) {
        self.frame_id = frame_id;
        self.timers.reset();
        self.samplers.reset();
        self.inside_frame = true;
    }

    fn end_frame(&mut self) {
        self.finish_timer();
        self.finish_sampler();
        self.inside_frame = false;
    }

    fn finish_timer(&mut self) {
        debug_assert!(self.inside_frame);
        if self.timers.pending != 0 {
            self.gl.end_query(gl::TIME_ELAPSED);
            self.timers.pending = 0;
        }
    }

    fn finish_sampler(&mut self) {
        debug_assert!(self.inside_frame);
        if self.samplers.pending != 0 {
            self.gl.end_query(gl::SAMPLES_PASSED);
            self.samplers.pending = 0;
        }
    }
}

impl<T: NamedTag> GpuFrameProfile<T> {
    fn start_timer(&mut self, tag: T) -> GpuTimeQuery {
        self.finish_timer();

        let marker = GpuMarker::new(&self.gl, tag.get_label());

        if let Some(query) = self.timers.add(GpuTimer { tag, time_ns: 0 }) {
            self.gl.begin_query(gl::TIME_ELAPSED, query);
        }

        GpuTimeQuery(marker)
    }

    fn start_sampler(&mut self, tag: T) -> GpuSampleQuery {
        self.finish_sampler();

        if let Some(query) = self.samplers.add(GpuSampler { tag, count: 0 }) {
            self.gl.begin_query(gl::SAMPLES_PASSED, query);
        }

        GpuSampleQuery
    }

    fn build_samples(&mut self) -> (FrameId, Vec<GpuTimer<T>>, Vec<GpuSampler<T>>) {
        debug_assert!(!self.inside_frame);
        let gl = &self.gl;

        (
            self.frame_id,
            self.timers.take(|timer, query| {
                timer.time_ns = gl.get_query_object_ui64v(query, gl::QUERY_RESULT)
            }),
            self.samplers.take(|sampler, query| {
                sampler.count = gl.get_query_object_ui64v(query, gl::QUERY_RESULT)
            }),
        )
    }
}

impl<T> Drop for GpuFrameProfile<T> {
    fn drop(&mut self) {
        self.disable_timers();
        self.disable_samplers();
    }
}

pub struct GpuProfiler<T> {
    gl: Rc<gl::Gl>,
    frames: Vec<GpuFrameProfile<T>>,
    next_frame: usize,
}

impl<T> GpuProfiler<T> {
    pub fn new(gl: Rc<gl::Gl>) -> Self {
        const MAX_PROFILE_FRAMES: usize = 4;
        let frames = (0 .. MAX_PROFILE_FRAMES)
            .map(|_| GpuFrameProfile::new(Rc::clone(&gl)))
            .collect();

        GpuProfiler {
            gl,
            next_frame: 0,
            frames,
        }
    }

    pub fn enable_timers(&mut self) {
        const MAX_TIMERS_PER_FRAME: i32 = 256;

        for frame in &mut self.frames {
            frame.enable_timers(MAX_TIMERS_PER_FRAME);
        }
    }

    pub fn disable_timers(&mut self) {
        for frame in &mut self.frames {
            frame.disable_timers();
        }
    }

    pub fn toggle_timers_enabled(&mut self) {
        if self.frames[0].timers.set.is_empty() {
            self.enable_timers();
        } else {
            self.disable_timers();
        }
    }

    pub fn enable_samplers(&mut self) {
        const MAX_SAMPLERS_PER_FRAME: i32 = 16;
        if cfg!(target_os = "macos") {
            warn!("Expect OSX driver bugs related to sample queries")
        }

        for frame in &mut self.frames {
            frame.enable_samplers(MAX_SAMPLERS_PER_FRAME);
        }
    }

    pub fn disable_samplers(&mut self) {
        for frame in &mut self.frames {
            frame.disable_samplers();
        }
    }

    pub fn toggle_samplers_enabled(&mut self) {
        if self.frames[0].samplers.set.is_empty() {
            self.enable_samplers();
        } else {
            self.disable_samplers();
        }
    }
}

impl<T: NamedTag> GpuProfiler<T> {
    pub fn build_samples(&mut self) -> (FrameId, Vec<GpuTimer<T>>, Vec<GpuSampler<T>>) {
        self.frames[self.next_frame].build_samples()
    }

    pub fn begin_frame(&mut self, frame_id: FrameId) {
        self.frames[self.next_frame].begin_frame(frame_id);
    }

    pub fn end_frame(&mut self) {
        self.frames[self.next_frame].end_frame();
        self.next_frame = (self.next_frame + 1) % self.frames.len();
    }

    pub fn start_timer(&mut self, tag: T) -> GpuTimeQuery {
        self.frames[self.next_frame].start_timer(tag)
    }

    pub fn start_sampler(&mut self, tag: T) -> GpuSampleQuery {
        self.frames[self.next_frame].start_sampler(tag)
    }

    pub fn finish_sampler(&mut self, _sampler: GpuSampleQuery) {
        self.frames[self.next_frame].finish_sampler()
    }

    pub fn start_marker(&mut self, label: &str) -> GpuMarker {
        GpuMarker::new(&self.gl, label)
    }

    pub fn place_marker(&mut self, label: &str) {
        GpuMarker::fire(&self.gl, label)
    }
}

#[must_use]
pub struct GpuMarker {
    gl: Option<Rc<gl::Gl>>,
}

impl GpuMarker {
    fn new(gl: &Rc<gl::Gl>, message: &str) -> Self {
        if gl.get_type() == gl::GlType::Gl {
            gl.push_group_marker_ext(message);
            GpuMarker { gl: Some(Rc::clone(gl)) }
        } else {
            GpuMarker { gl: None }
        }
    }

    fn fire(gl: &Rc<gl::Gl>, message: &str) {
        if gl.get_type() == gl::GlType::Gl {
            gl.insert_event_marker_ext(message);
        }
    }
}

impl Drop for GpuMarker {
    fn drop(&mut self) {
        if let Some(ref gl) = self.gl {
            gl.pop_group_marker_ext();
        }
    }
}

#[must_use]
pub struct GpuTimeQuery(GpuMarker);
#[must_use]
pub struct GpuSampleQuery;
<|endoftext|>


<commit_before>use tcod::colors::{Color};

use traits::{Renderable, Movable, Position};
use Direction;
use point::Point;
use map;
use map::Map;

use std::fs::File;
use std::path::Path;

use rand;
use rand::Rng;
use rand::distributions::{Weighted};

use serde_yaml;

const ERR_UNIT_LOAD: &str = "Unable to load unit type data.";

#[derive(Debug)]
pub struct UnitType {
    name: String,
    glyph: char,
    color: Color,
    is_blocking: bool,
    max_hp: u8,
    defence: u8,
    attack: u8,
}

impl UnitType {
    // Only used for the player for now.
    pub fn new(name: &str, glyph: char, color: Color) -> UnitType {
        UnitType {
            name: name.into(),
            glyph: glyph,
            color: color,
            is_blocking: true,
            // Following based on standard human in the data files.
            max_hp: 30,
            defence: 3,
            attack: 5,
        }
    }
}

impl<'a> From<&'a UnitTypeRaw> for UnitType {
    fn from(raw: &'a UnitTypeRaw) -> UnitType {
        UnitType {
            name: raw.name.clone(),
            glyph: raw.glyph,
            color: Color::new(raw.color[0], raw.color[1], raw.color[2]),
            is_blocking: raw.is_blocking,
            max_hp: raw.max_hp,
            defence: raw.defence,
            attack: raw.attack,
        }
    }
}

// The Color type in tcod isn't deserializable, so have this to make reading
// the data file easier.
#[derive(Debug, Deserialize)]
struct UnitTypeRaw {
    name: String,
    glyph: char,
    color: [u8; 3],
    chance: u32,
    is_blocking: bool,
    max_hp: u8,
    defence: u8,
    attack: u8,
}

pub struct UnitTypeLists {
    pub types: Vec<UnitType>,
    weights: Vec<Weighted<usize>>,
    max_weight: u32,
}

impl UnitTypeLists {
    pub fn get_random_type(&self, rng: &mut rand::ThreadRng) -> &UnitType {
        let mut val = rng.gen_range(0, self.max_weight);

        for weight in self.weights.iter() {
            if weight.weight > val {
                return &self.types[weight.item];
            }

            val -= weight.weight;
        }

        unreachable!()
    }
}

pub fn load_unit_types() -> UnitTypeLists{
    let path = Path::new("data").join("unit_types.yaml");
    let data_file = File::open(&path).expect(ERR_UNIT_LOAD);
    let raw_units: Vec<UnitTypeRaw> = serde_yaml::from_reader(&data_file).expect(ERR_UNIT_LOAD);

    let mut types = vec![];
    let mut weights = vec![];

    let mut running_total = 0;
    for (i, raw_unit) in raw_units.iter().enumerate() {
        types.push(raw_unit.into());
        running_total += raw_unit.chance;

        weights.push( Weighted{ weight: raw_unit.chance, item: i });
    }

    UnitTypeLists {
        types: types,
        weights: weights,
        max_weight: running_total,
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AttackResult {
    Dead,
    Alive,
    NoEffect,
}

#[derive(Debug)]
pub struct Unit<'a> {
    position: Point<i16>,
    unit_type: &'a UnitType,
    cur_hp: u8,
}

impl<'a> Unit<'a> {
    pub fn new(pos: Point<i16>, unit_type: &'a UnitType) -> Unit<'a> {
        let cur_hp = unit_type.max_hp;
        Unit {
            position: pos,
            unit_type: unit_type,
            cur_hp: cur_hp,
        }
    }

    pub fn is_blocking(&self) -> bool {
        self.unit_type.is_blocking
    }

    pub fn get_name(&self) -> &str {
        &self.unit_type.name
    }

    pub fn get_hp(&self) -> u8 {
        self.cur_hp
    }

    fn get_step_towards(&mut self, target: Point<i16>) -> Point<i16> {
        let cur_pos = self.get_position();
        let delta = target - cur_pos;
        let dist = delta.radius();

        let new_pos = Point {
            x: (delta.x as f64 / dist).round() as i16,
            y: (delta.y as f64 / dist).round() as i16,
        };
        new_pos + cur_pos
    }

    pub fn take_turn(&mut self, map: &Map, player: &mut Unit) {
        if !map.point_in_fov(self.get_position()) {
            return;
        }

        if (self.get_position() - player.get_position()).radius() >= 2.0 {
            let new_pos = self.get_step_towards(player.get_position());
            if map.can_move_to(new_pos) == map::CanMoveResponse::Open {
                self.move_to(new_pos);
            }
        } else if player.get_hp() > 0 {
            self.attack(player);
        }
    }

    pub fn take_damage(&mut self, damage: u8) -> AttackResult {
        if let Some(new_hp) = self.cur_hp.checked_sub(damage) {
            self.cur_hp = new_hp;
            AttackResult::Alive
        } else {
            AttackResult::Dead
        }
    }

    pub fn attack(&self, target: &mut Unit) -> AttackResult {
        if let Some(damage) = self.unit_type.attack.checked_sub(target.unit_type.defence) {
            println!("{} attacks {} for {} damage.", self.get_name(), target.get_name(), damage);
            target.take_damage(damage)
        } else {
            println!("{} attacks {}, but it has no effect!", self.get_name(), target.get_name());
            AttackResult::NoEffect
        }
    }
}

impl<'a> Position for Unit<'a> {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl<'a> Renderable for Unit<'a> {
    fn get_color(&self) -> Color {
        self.unit_type.color
    }

    fn get_glyph(&self) -> char {
        self.unit_type.glyph
    }
}

impl<'a> Movable for Unit<'a> {
    fn move_to(&mut self, pos: Point<i16>){
        self.position = pos;
    }
    fn nudge(&mut self, dir: Direction){
        self.position = self.position + dir.to_rel_point();
    }
}<commit_msg>Set HP to 0 when dead.<commit_after>use tcod::colors::{Color};

use traits::{Renderable, Movable, Position};
use Direction;
use point::Point;
use map;
use map::Map;

use std::fs::File;
use std::path::Path;

use rand;
use rand::Rng;
use rand::distributions::{Weighted};

use serde_yaml;

const ERR_UNIT_LOAD: &str = "Unable to load unit type data.";

#[derive(Debug)]
pub struct UnitType {
    name: String,
    glyph: char,
    color: Color,
    is_blocking: bool,
    max_hp: u8,
    defence: u8,
    attack: u8,
}

impl UnitType {
    // Only used for the player for now.
    pub fn new(name: &str, glyph: char, color: Color) -> UnitType {
        UnitType {
            name: name.into(),
            glyph: glyph,
            color: color,
            is_blocking: true,
            // Following based on standard human in the data files.
            max_hp: 30,
            defence: 3,
            attack: 5,
        }
    }
}

impl<'a> From<&'a UnitTypeRaw> for UnitType {
    fn from(raw: &'a UnitTypeRaw) -> UnitType {
        UnitType {
            name: raw.name.clone(),
            glyph: raw.glyph,
            color: Color::new(raw.color[0], raw.color[1], raw.color[2]),
            is_blocking: raw.is_blocking,
            max_hp: raw.max_hp,
            defence: raw.defence,
            attack: raw.attack,
        }
    }
}

// The Color type in tcod isn't deserializable, so have this to make reading
// the data file easier.
#[derive(Debug, Deserialize)]
struct UnitTypeRaw {
    name: String,
    glyph: char,
    color: [u8; 3],
    chance: u32,
    is_blocking: bool,
    max_hp: u8,
    defence: u8,
    attack: u8,
}

pub struct UnitTypeLists {
    pub types: Vec<UnitType>,
    weights: Vec<Weighted<usize>>,
    max_weight: u32,
}

impl UnitTypeLists {
    pub fn get_random_type(&self, rng: &mut rand::ThreadRng) -> &UnitType {
        let mut val = rng.gen_range(0, self.max_weight);

        for weight in self.weights.iter() {
            if weight.weight > val {
                return &self.types[weight.item];
            }

            val -= weight.weight;
        }

        unreachable!()
    }
}

pub fn load_unit_types() -> UnitTypeLists{
    let path = Path::new("data").join("unit_types.yaml");
    let data_file = File::open(&path).expect(ERR_UNIT_LOAD);
    let raw_units: Vec<UnitTypeRaw> = serde_yaml::from_reader(&data_file).expect(ERR_UNIT_LOAD);

    let mut types = vec![];
    let mut weights = vec![];

    let mut running_total = 0;
    for (i, raw_unit) in raw_units.iter().enumerate() {
        types.push(raw_unit.into());
        running_total += raw_unit.chance;

        weights.push( Weighted{ weight: raw_unit.chance, item: i });
    }

    UnitTypeLists {
        types: types,
        weights: weights,
        max_weight: running_total,
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AttackResult {
    Dead,
    Alive,
    NoEffect,
}

#[derive(Debug)]
pub struct Unit<'a> {
    position: Point<i16>,
    unit_type: &'a UnitType,
    cur_hp: u8,
}

impl<'a> Unit<'a> {
    pub fn new(pos: Point<i16>, unit_type: &'a UnitType) -> Unit<'a> {
        let cur_hp = unit_type.max_hp;
        Unit {
            position: pos,
            unit_type: unit_type,
            cur_hp: cur_hp,
        }
    }

    pub fn is_blocking(&self) -> bool {
        self.unit_type.is_blocking
    }

    pub fn get_name(&self) -> &str {
        &self.unit_type.name
    }

    pub fn get_hp(&self) -> u8 {
        self.cur_hp
    }

    fn get_step_towards(&mut self, target: Point<i16>) -> Point<i16> {
        let cur_pos = self.get_position();
        let delta = target - cur_pos;
        let dist = delta.radius();

        let new_pos = Point {
            x: (delta.x as f64 / dist).round() as i16,
            y: (delta.y as f64 / dist).round() as i16,
        };
        new_pos + cur_pos
    }

    pub fn take_turn(&mut self, map: &Map, player: &mut Unit) {
        if !map.point_in_fov(self.get_position()) {
            return;
        }

        if (self.get_position() - player.get_position()).radius() >= 2.0 {
            let new_pos = self.get_step_towards(player.get_position());
            if map.can_move_to(new_pos) == map::CanMoveResponse::Open {
                self.move_to(new_pos);
            }
        } else if player.get_hp() > 0 {
            self.attack(player);
        }
    }

    pub fn take_damage(&mut self, damage: u8) -> AttackResult {
        if let Some(new_hp) = self.cur_hp.checked_sub(damage) {
            self.cur_hp = new_hp;
            AttackResult::Alive
        } else {
            self.cur_hp = 0;
            AttackResult::Dead
        }
    }

    pub fn attack(&self, target: &mut Unit) -> AttackResult {
        if let Some(damage) = self.unit_type.attack.checked_sub(target.unit_type.defence) {
            println!("{} attacks {} for {} damage.", self.get_name(), target.get_name(), damage);
            target.take_damage(damage)
        } else {
            println!("{} attacks {}, but it has no effect!", self.get_name(), target.get_name());
            AttackResult::NoEffect
        }
    }
}

impl<'a> Position for Unit<'a> {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl<'a> Renderable for Unit<'a> {
    fn get_color(&self) -> Color {
        self.unit_type.color
    }

    fn get_glyph(&self) -> char {
        self.unit_type.glyph
    }
}

impl<'a> Movable for Unit<'a> {
    fn move_to(&mut self, pos: Point<i16>){
        self.position = pos;
    }
    fn nudge(&mut self, dir: Direction){
        self.position = self.position + dir.to_rel_point();
    }
}<|endoftext|>


<commit_before>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs,
    ops::Range,
    path::{Path, PathBuf},
    sync::Mutex,
};

use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[""]]
#[macro_export]
macro_rules! expect {
    [[$lit:literal]] => {$crate::Expect {
        file: file!(),
        line: line!(),
        column: column!(),
        data: $lit,
    }};
    [[]] => { $crate::expect![[""]] };
}

#[derive(Debug)]
pub struct Expect {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
    pub data: &'static str,
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length = file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        let mut updated = "";
        if update_expect() {
            updated = " (updated)";
            rt.per_file
                .entry(expect.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
        }
        let print_help = !rt.help_printed && !update_expect();
        rt.help_printed = true;

        let help = if print_help { HELP } else { "" };
        println!(
            "\n
error: expect test failed{}
  --> {}:{}:{}
{}
Expect:
----
{}
----

Actual:
----
{}
----
",
            updated, expect.file, expect.line, expect.column, help, expected, actual
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        std::panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos += insert;
            **pos -= delete
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_expect_macro() {
        let empty = expect![[]];
        expect![[r#"
            Expect {
                file: "crates/expect/src/lib.rs",
                line: 241,
                column: 21,
                data: "",
            }
        "#]]
        .assert_debug_eq(&empty);

        let expect = expect![["
            hello
            world
        "]];
        expect![[r#"
            Expect {
                file: "crates/expect/src/lib.rs",
                line: 252,
                column: 22,
                data: "\n            hello\n            world\n        ",
            }
        "#]]
        .assert_debug_eq(&expect);
    }

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<commit_msg>Remove fragile test<commit_after>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs,
    ops::Range,
    path::{Path, PathBuf},
    sync::Mutex,
};

use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[""]]
#[macro_export]
macro_rules! expect {
    [[$lit:literal]] => {$crate::Expect {
        file: file!(),
        line: line!(),
        column: column!(),
        data: $lit,
    }};
    [[]] => { $crate::expect![[""]] };
}

#[derive(Debug)]
pub struct Expect {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
    pub data: &'static str,
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length =
            file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        let mut updated = "";
        if update_expect() {
            updated = " (updated)";
            rt.per_file
                .entry(expect.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
        }
        let print_help = !rt.help_printed && !update_expect();
        rt.help_printed = true;

        let help = if print_help { HELP } else { "" };
        println!(
            "\n
error: expect test failed{}
  --> {}:{}:{}
{}
Expect:
----
{}
----

Actual:
----
{}
----
",
            updated, expect.file, expect.line, expect.column, help, expected, actual
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        std::panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos += insert;
            **pos -= delete
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Implement the 'Dining Philosophers' in one go.<commit_after>use std::thread;
use std::sync::{Mutex, Arc};

struct Philosopher {
    name: String,
    left: usize,
    right: usize,
}

impl Philosopher {
    fn new(name: &str, left: usize, right: usize) -> Philosopher {
        Philosopher {
            name: name.to_string(),
            left: left,
            right: right,
        }
    }

    fn eat(&self, table: &Table) {
        let _left = table.forks[self.left].lock().unwrap();
        let _right = table.forks[self.right].lock().unwrap();

        println!("{} is eating.", self.name);

        thread::sleep_ms(1000);

        println!("{} is done eating.", self.name);
    }
}

struct Table {
    forks: Vec<Mutex<()>>,
}

fn main() {
    let table = Arc::new(Table { forks: vec![
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
        Mutex::new(()),
    ]});

    let philosophers = vec![
        Philosopher::new("Baruch Spinoza", 0, 1),
        Philosopher::new("Gilles Deleuze", 1, 2),
        Philosopher::new("Karl Marx", 2, 3),
        Philosopher::new("Friedrich Nietzsche", 3, 4),
        Philosopher::new("Michel Foucault", 0, 4),
    ];

    let handles: Vec<_> = philosophers.into_iter().map(|p| {
        let table = table.clone();

        thread::spawn(move || {
            p.eat(&table);
        })
    }).collect();

    for h in handles {
        h.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher};

use criterion::*;
use fxhash::FxHasher;

use ahash::{AHasher, CallHasher, HasherExt};

fn gen_word_pairs() -> Vec<String> {
    let words: Vec<_> = r#"
a, ability, able, about, above, accept, according, account, across, act, action,
activity, actually, add, address, administration, admit, adult, affect, after,
again, against, age, agency, agent, ago, agree, agreement, ahead, air, all,
allow, almost, alone, along, already, also, although, always, American, among,
amount, analysis, and, animal, another, answer, any, anyone, anything, appear,
apply, approach, area, argue, arm, around, arrive, art, article, artist, as,
ask, assume, at, attack, attention, attorney, audience, author, authority,
available, avoid, away, baby, back, bad, bag, ball, bank, bar, base, be, beat,
beautiful, because, become, bed, before, begin, behavior, behind, believe,
benefit, best, better, between, beyond, big, bill, billion, bit, black, blood,
blue, board, body, book, born, both, box, boy, break, bring, brother, budget,
build, building, business, but, buy, by, call, camera, campaign, can, cancer,
candidate, capital, car, card, care, career, carry, case, catch, cause, cell,
center, central, century, certain, certainly, chair, challenge, chance, change,
character, charge, check, child, choice, choose, church, citizen, city, civil,
claim, class, clear, clearly, close, coach, cold, collection, college, color,
come, commercial, common, community, company, compare, computer, concern,
condition, conference, Congress, consider, consumer, contain, continue, control,
cost, could, country, couple, course, court, cover, create, crime, cultural,
culture, cup, current, customer, cut, dark, data, daughter, day, dead, deal,
death, debate, decade, decide, decision, deep, defense, degree, Democrat,
democratic, describe, design, despite, detail, determine, develop, development,
die, difference, different, difficult, dinner, direction, director, discover,
discuss, discussion, disease, do, doctor, dog, door, down, draw, dream, drive,
drop, drug, during, each, early, east, easy, eat, economic, economy, edge,
education, effect, effort, eight, either, election, else, employee, end, energy,
enjoy, enough, enter, entire, environment, environmental, especially, establish,
even, evening, event, ever, every, everybody, everyone, everything, evidence,
exactly, example, executive, exist, expect, experience, expert, explain, eye,
face, fact, factor, fail, fall, family, far, fast, father, fear, federal, feel,
feeling, few, field, fight, figure, fill, film, final, finally, financial, find,
fine, finger, finish, fire, firm, first, fish, five, floor, fly, focus, follow,
food, foot, for, force, foreign, forget, form, former, forward, four, free,
friend, from, front, full, fund, future, game, garden, gas, general, generation,
get, girl, give, glass, go, goal, good, government, great, green, ground, group,
grow, growth, guess, gun, guy, hair, half, hand, hang, happen, happy, hard,
have, he, head, health, hear, heart, heat, heavy, help, her, here, herself,
high, him, himself, his, history, hit, hold, home, hope, hospital, hot, hotel,
hour, house, how, however, huge, human, hundred, husband, I, idea, identify, if,
image, imagine, impact, important, improve, in, include, including, increase,
indeed, indicate, individual, industry, information, inside, instead,
institution, interest, interesting, international, interview, into, investment,
involve, issue, it, item, its, itself, job, join, just, keep, key, kid, kill,
kind, kitchen, know, knowledge, land, language, large, last, late, later, laugh,
law, lawyer, lay, lead, leader, learn, least, leave, left, leg, legal, less,
let, letter, level, lie, life, light, like, likely, line, list, listen, little,
live, local, long, look, lose, loss, lot, love, low, machine, magazine, main,
maintain, major, majority, make, man, manage, management, manager, many, market,
marriage, material, matter, may, maybe, me, mean, measure, media, medical, meet,
meeting, member, memory, mention, message, method, middle, might, military,
million, mind, minute, miss, mission, model, modern, moment, money, month, more,
morning, most, mother, mouth, move, movement, movie, Mr, Mrs, much, music, must,
my, myself, name, nation, national, natural, nature, near, nearly, necessary,
need, network, never, new, news, newspaper, next, nice, night, no, none, nor,
north, not, note, nothing, notice, now, n't, number, occur, of, off, offer,
office, officer, official, often, oh, oil, ok, old, on, once, one, only, onto,
open, operation, opportunity, option, or, order, organization, other, others,
our, out, outside, over, own, owner, page, pain, painting, paper, parent, part,
participant, particular, particularly, partner, party, pass, past, patient,
pattern, pay, peace, people, per, perform, performance, perhaps, period, person,
personal, phone, physical, pick, picture, piece, place, plan, plant, play,
player, PM, point, police, policy, political, politics, poor, popular,
population, position, positive, possible, power, practice, prepare, present,
president, pressure, pretty, prevent, price, private, probably, problem,
process, produce, product, production, professional, professor, program,
project, property, protect, prove, provide, public, pull, purpose, push, put,
quality, question, quickly, quite, race, radio, raise, range, rate, rather,
reach, read, ready, real, reality, realize, really, reason, receive, recent,
recently, recognize, record, red, reduce, reflect, region, relate, relationship,
religious, remain, remember, remove, report, represent, Republican, require,
research, resource, respond, response, responsibility, rest, result, return,
reveal, rich, right, rise, risk, road, rock, role, room, rule, run, safe, same,
save, say, scene, school, science, scientist, score, sea, season, seat, second,
section, security, see, seek, seem, sell, send, senior, sense, series, serious,
serve, service, set, seven, several, sex, sexual, shake, share, she, shoot,
short, shot, should, shoulder, show, side, sign, significant, similar, simple,
simply, since, sing, single, sister, sit, site, situation, six, size, skill,
skin, small, smile, so, social, society, soldier, some, somebody, someone,
something, sometimes, son, song, soon, sort, sound, source, south, southern,
space, speak, special, specific, speech, spend, sport, spring, staff, stage,
stand, standard, star, start, state, statement, station, stay, step, still,
stock, stop, store, story, strategy, street, strong, structure, student, study,
stuff, style, subject, success, successful, such, suddenly, suffer, suggest,
summer, support, sure, surface, system, table, take, talk, task, tax, teach,
teacher, team, technology, television, tell, ten, tend, term, test, than, thank,
that, the, their, them, themselves, then, theory, there, these, they, thing,
think, third, this, those, though, thought, thousand, threat, three, through,
throughout, throw, thus, time, to, today, together, tonight, too, top, total,
tough, toward, town, trade, traditional, training, travel, treat, treatment,
tree, trial, trip, trouble, true, truth, try, turn, TV, two, type, under,
understand, unit, until, up, upon, us, use, usually, value, various, very,
victim, view, violence, visit, voice, vote, wait, walk, wall, want, war, watch,
water, way, we, weapon, wear, week, weight, well, west, western, what, whatever,
when, where, whether, which, while, white, who, whole, whom, whose, why, wide,
wife, will, win, wind, window, wish, with, within, without, woman, wonder, word,
work, worker, world, worry, would, write, writer, wrong, yard, yeah, year, yes,
yet, you, young, your, yourself"#
        .split(',')
        .map(|word| word.trim())
        .collect();

    let mut word_pairs: Vec<_> = Vec::new();
    for word in &words {
        for other_word in &words {
            word_pairs.push(word.to_string() + " " + other_word);
        }
    }
    assert_eq!(1_000_000, word_pairs.len());
    word_pairs
}

#[allow(unused)] // False positive
fn test_hash_common_words<T: HasherExt>(hasher: impl Fn() -> T) {
    let word_pairs: Vec<_> = gen_word_pairs();
    check_for_collisions(&hasher, &word_pairs, 32);
}

#[allow(unused)] // False positive
fn check_for_collisions<T: HasherExt, H: Hash>(hasher: &impl Fn() -> T, items: &[H], bucket_count: usize) {
    let mut buckets = vec![0; bucket_count];
    for item in items {
        let value = hash(item, &hasher) as usize;
        println!("{:x}", value);
        buckets[value % bucket_count] += 1;
    }
    let mean = items.len() / bucket_count;
    let max = *buckets.iter().max().unwrap();
    let min = *buckets.iter().min().unwrap();
    assert!(
        (min as f64) > (mean as f64) * 0.95,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
    assert!(
        (max as f64) < (mean as f64) * 1.05,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
}

#[allow(unused)] // False positive
fn hash<T: HasherExt>(b: &impl Hash, hasher: &dyn Fn() -> T) -> u64 {
    let hasher = hasher();
    b.get_hash(hasher)
}

#[test]
fn test_bucket_distribution() {
    let hasher = || AHasher::new_with_keys(12, 34);
    test_hash_common_words(&hasher);
    let sequence: Vec<_> = (0..320000).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000).collect();
    check_for_collisions(&hasher, &sequence, 256);
    let sequence: Vec<_> = (0..320000).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000_u64).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 256);
}

fn ahash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = AHasher::new_with_keys(1234, 5678);
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn fxhash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = FxHasher::default();
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn bench_ahash_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("aes_words", |b| b.iter(|| black_box(ahash_vec(&words))));
}

fn bench_fx_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("fx_words", |b| b.iter(|| black_box(fxhash_vec(&words))));
}

criterion_main!(benches);
criterion_group!(benches, bench_ahash_words, bench_fx_words,);
<commit_msg>Fix overly bad keys in test<commit_after>use std::hash::{Hash, Hasher};

use criterion::*;
use fxhash::FxHasher;

use ahash::{AHasher, CallHasher, HasherExt};

fn gen_word_pairs() -> Vec<String> {
    let words: Vec<_> = r#"
a, ability, able, about, above, accept, according, account, across, act, action,
activity, actually, add, address, administration, admit, adult, affect, after,
again, against, age, agency, agent, ago, agree, agreement, ahead, air, all,
allow, almost, alone, along, already, also, although, always, American, among,
amount, analysis, and, animal, another, answer, any, anyone, anything, appear,
apply, approach, area, argue, arm, around, arrive, art, article, artist, as,
ask, assume, at, attack, attention, attorney, audience, author, authority,
available, avoid, away, baby, back, bad, bag, ball, bank, bar, base, be, beat,
beautiful, because, become, bed, before, begin, behavior, behind, believe,
benefit, best, better, between, beyond, big, bill, billion, bit, black, blood,
blue, board, body, book, born, both, box, boy, break, bring, brother, budget,
build, building, business, but, buy, by, call, camera, campaign, can, cancer,
candidate, capital, car, card, care, career, carry, case, catch, cause, cell,
center, central, century, certain, certainly, chair, challenge, chance, change,
character, charge, check, child, choice, choose, church, citizen, city, civil,
claim, class, clear, clearly, close, coach, cold, collection, college, color,
come, commercial, common, community, company, compare, computer, concern,
condition, conference, Congress, consider, consumer, contain, continue, control,
cost, could, country, couple, course, court, cover, create, crime, cultural,
culture, cup, current, customer, cut, dark, data, daughter, day, dead, deal,
death, debate, decade, decide, decision, deep, defense, degree, Democrat,
democratic, describe, design, despite, detail, determine, develop, development,
die, difference, different, difficult, dinner, direction, director, discover,
discuss, discussion, disease, do, doctor, dog, door, down, draw, dream, drive,
drop, drug, during, each, early, east, easy, eat, economic, economy, edge,
education, effect, effort, eight, either, election, else, employee, end, energy,
enjoy, enough, enter, entire, environment, environmental, especially, establish,
even, evening, event, ever, every, everybody, everyone, everything, evidence,
exactly, example, executive, exist, expect, experience, expert, explain, eye,
face, fact, factor, fail, fall, family, far, fast, father, fear, federal, feel,
feeling, few, field, fight, figure, fill, film, final, finally, financial, find,
fine, finger, finish, fire, firm, first, fish, five, floor, fly, focus, follow,
food, foot, for, force, foreign, forget, form, former, forward, four, free,
friend, from, front, full, fund, future, game, garden, gas, general, generation,
get, girl, give, glass, go, goal, good, government, great, green, ground, group,
grow, growth, guess, gun, guy, hair, half, hand, hang, happen, happy, hard,
have, he, head, health, hear, heart, heat, heavy, help, her, here, herself,
high, him, himself, his, history, hit, hold, home, hope, hospital, hot, hotel,
hour, house, how, however, huge, human, hundred, husband, I, idea, identify, if,
image, imagine, impact, important, improve, in, include, including, increase,
indeed, indicate, individual, industry, information, inside, instead,
institution, interest, interesting, international, interview, into, investment,
involve, issue, it, item, its, itself, job, join, just, keep, key, kid, kill,
kind, kitchen, know, knowledge, land, language, large, last, late, later, laugh,
law, lawyer, lay, lead, leader, learn, least, leave, left, leg, legal, less,
let, letter, level, lie, life, light, like, likely, line, list, listen, little,
live, local, long, look, lose, loss, lot, love, low, machine, magazine, main,
maintain, major, majority, make, man, manage, management, manager, many, market,
marriage, material, matter, may, maybe, me, mean, measure, media, medical, meet,
meeting, member, memory, mention, message, method, middle, might, military,
million, mind, minute, miss, mission, model, modern, moment, money, month, more,
morning, most, mother, mouth, move, movement, movie, Mr, Mrs, much, music, must,
my, myself, name, nation, national, natural, nature, near, nearly, necessary,
need, network, never, new, news, newspaper, next, nice, night, no, none, nor,
north, not, note, nothing, notice, now, n't, number, occur, of, off, offer,
office, officer, official, often, oh, oil, ok, old, on, once, one, only, onto,
open, operation, opportunity, option, or, order, organization, other, others,
our, out, outside, over, own, owner, page, pain, painting, paper, parent, part,
participant, particular, particularly, partner, party, pass, past, patient,
pattern, pay, peace, people, per, perform, performance, perhaps, period, person,
personal, phone, physical, pick, picture, piece, place, plan, plant, play,
player, PM, point, police, policy, political, politics, poor, popular,
population, position, positive, possible, power, practice, prepare, present,
president, pressure, pretty, prevent, price, private, probably, problem,
process, produce, product, production, professional, professor, program,
project, property, protect, prove, provide, public, pull, purpose, push, put,
quality, question, quickly, quite, race, radio, raise, range, rate, rather,
reach, read, ready, real, reality, realize, really, reason, receive, recent,
recently, recognize, record, red, reduce, reflect, region, relate, relationship,
religious, remain, remember, remove, report, represent, Republican, require,
research, resource, respond, response, responsibility, rest, result, return,
reveal, rich, right, rise, risk, road, rock, role, room, rule, run, safe, same,
save, say, scene, school, science, scientist, score, sea, season, seat, second,
section, security, see, seek, seem, sell, send, senior, sense, series, serious,
serve, service, set, seven, several, sex, sexual, shake, share, she, shoot,
short, shot, should, shoulder, show, side, sign, significant, similar, simple,
simply, since, sing, single, sister, sit, site, situation, six, size, skill,
skin, small, smile, so, social, society, soldier, some, somebody, someone,
something, sometimes, son, song, soon, sort, sound, source, south, southern,
space, speak, special, specific, speech, spend, sport, spring, staff, stage,
stand, standard, star, start, state, statement, station, stay, step, still,
stock, stop, store, story, strategy, street, strong, structure, student, study,
stuff, style, subject, success, successful, such, suddenly, suffer, suggest,
summer, support, sure, surface, system, table, take, talk, task, tax, teach,
teacher, team, technology, television, tell, ten, tend, term, test, than, thank,
that, the, their, them, themselves, then, theory, there, these, they, thing,
think, third, this, those, though, thought, thousand, threat, three, through,
throughout, throw, thus, time, to, today, together, tonight, too, top, total,
tough, toward, town, trade, traditional, training, travel, treat, treatment,
tree, trial, trip, trouble, true, truth, try, turn, TV, two, type, under,
understand, unit, until, up, upon, us, use, usually, value, various, very,
victim, view, violence, visit, voice, vote, wait, walk, wall, want, war, watch,
water, way, we, weapon, wear, week, weight, well, west, western, what, whatever,
when, where, whether, which, while, white, who, whole, whom, whose, why, wide,
wife, will, win, wind, window, wish, with, within, without, woman, wonder, word,
work, worker, world, worry, would, write, writer, wrong, yard, yeah, year, yes,
yet, you, young, your, yourself"#
        .split(',')
        .map(|word| word.trim())
        .collect();

    let mut word_pairs: Vec<_> = Vec::new();
    for word in &words {
        for other_word in &words {
            word_pairs.push(word.to_string() + " " + other_word);
        }
    }
    assert_eq!(1_000_000, word_pairs.len());
    word_pairs
}

#[allow(unused)] // False positive
fn test_hash_common_words<T: HasherExt>(hasher: impl Fn() -> T) {
    let word_pairs: Vec<_> = gen_word_pairs();
    check_for_collisions(&hasher, &word_pairs, 32);
}

#[allow(unused)] // False positive
fn check_for_collisions<T: HasherExt, H: Hash>(hasher: &impl Fn() -> T, items: &[H], bucket_count: usize) {
    let mut buckets = vec![0; bucket_count];
    for item in items {
        let value = hash(item, &hasher) as usize;
        buckets[value % bucket_count] += 1;
    }
    let mean = items.len() / bucket_count;
    let max = *buckets.iter().max().unwrap();
    let min = *buckets.iter().min().unwrap();
    assert!(
        (min as f64) > (mean as f64) * 0.95,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
    assert!(
        (max as f64) < (mean as f64) * 1.05,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
}

#[allow(unused)] // False positive
fn hash<T: HasherExt>(b: &impl Hash, hasher: &dyn Fn() -> T) -> u64 {
    let hasher = hasher();
    b.get_hash(hasher)
}

#[test]
fn test_bucket_distribution() {
    let hasher = || AHasher::new_with_keys(123456789, 987654321);
    test_hash_common_words(&hasher);
    let sequence: Vec<_> = (0..320000).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000).collect();
    check_for_collisions(&hasher, &sequence, 256);
    let sequence: Vec<_> = (0..320000).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000_u64).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 256);
}

fn ahash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = AHasher::new_with_keys(1234, 5678);
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn fxhash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = FxHasher::default();
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn bench_ahash_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("aes_words", |b| b.iter(|| black_box(ahash_vec(&words))));
}

fn bench_fx_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("fx_words", |b| b.iter(|| black_box(fxhash_vec(&words))));
}

criterion_main!(benches);
criterion_group!(benches, bench_ahash_words, bench_fx_words,);
<|endoftext|>


<commit_before>extern crate piston;
extern crate dyon;
extern crate current;
extern crate graphics;

use std::any::Any;
use std::sync::Arc;
use self::dyon::*;
use self::current::Current;
use self::piston::input::*;
use self::piston::window::*;
use self::graphics::{Context, Graphics};

pub const NO_EVENT: &'static str = "No event";

pub fn add_functions<W: Any + AdvancedWindow>(module: &mut Module) {
    module.add(Arc::new("render".into()), render, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("update".into()), update, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("press".into()), press, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("release".into()), release, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("focus".into()), focus, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool,
    });
    module.add(Arc::new("focus_arg".into()), focus_arg, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool,
    });
    module.add(Arc::new("set_title".into()),
        set_title::<W>, PreludeFunction {
            lts: vec![Lt::Default],
            tys: vec![Type::Text],
            ret: Type::Void
        });
    module.add(Arc::new("update_dt".into()),
        update_dt, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::F64
        });
    module.add(Arc::new("press_keyboard_key".into()),
        press_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::F64
        });
    module.add(Arc::new("release_keyboard_key".into()),
        release_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::F64
        });
}

pub fn render(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).render_args().is_some() });
    Ok(())
}

pub fn update(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().is_some() });
    Ok(())
}

pub fn press(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).press_args().is_some() });
    Ok(())
}

pub fn release(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).release_args().is_some() });
    Ok(())
}

pub fn focus(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args().is_some() });
    Ok(())
}

pub fn focus_arg(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args() });
    Ok(())
}

pub fn update_dt(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().map(|args| args.dt) });
    Ok(())
}

pub fn press_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.press_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn release_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.release_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn set_title<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
    use std::sync::Arc;

    let window = unsafe { &mut *Current::<W>::new() };
    let title: Arc<String> = try!(rt.pop());
    window.set_title((*title).clone());
    Ok(())
}

pub fn draw_2d<G: Graphics>(rt: &mut Runtime, c: Context, g: &mut G) -> Result<(), String> {
    use self::graphics::*;

    let draw_list = rt.stack.pop().expect("There is no value on the stack");
    let arr = rt.resolve(&draw_list);
    if let &Variable::Array(ref arr) = arr {
        for it in &**arr {
            let it = rt.resolve(it);
            if let &Variable::Array(ref it) = it {
                let ty: Arc<String> = try!(rt.var(&it[0]));
                match &**ty {
                    "clear" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        clear(color, g);
                    }
                    "line_color_radius_from_to" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let radius: f64 = try!(rt.var(&it[2]));
                        let from: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let to: [f64; 2] = try!(rt.var_vec4(&it[4]));
                        line(color, radius, [from[0], from[1], to[0], to[1]], c.transform, g);
                    }
                    "rectangle_color_corner_size" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        rectangle(color, [corner[0], corner[1], size[0], size[1]], c.transform, g);
                    }
                    "ellipse_color_corner_size_resolution" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let resolution: u32 = try!(rt.var(&it[4]));
                        Ellipse::new(color)
                        .resolution(resolution as u32)
                        .draw([corner[0], corner[1], size[0], size[1]], &c.draw_state, c.transform, g);
                    }
                    _ => {}
                }
            }
        }
    }
    return Ok(())
}
<commit_msg>Fixed types for "press_keyboard_key" and "release_keyboard_key"<commit_after>extern crate piston;
extern crate dyon;
extern crate current;
extern crate graphics;

use std::any::Any;
use std::sync::Arc;
use self::dyon::*;
use self::current::Current;
use self::piston::input::*;
use self::piston::window::*;
use self::graphics::{Context, Graphics};

pub const NO_EVENT: &'static str = "No event";

pub fn add_functions<W: Any + AdvancedWindow>(module: &mut Module) {
    module.add(Arc::new("render".into()), render, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("update".into()), update, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("press".into()), press, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("release".into()), release, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool
    });
    module.add(Arc::new("focus".into()), focus, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool,
    });
    module.add(Arc::new("focus_arg".into()), focus_arg, PreludeFunction {
        lts: vec![],
        tys: vec![],
        ret: Type::Bool,
    });
    module.add(Arc::new("set_title".into()),
        set_title::<W>, PreludeFunction {
            lts: vec![Lt::Default],
            tys: vec![Type::Text],
            ret: Type::Void
        });
    module.add(Arc::new("update_dt".into()),
        update_dt, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::F64
        });
    module.add(Arc::new("press_keyboard_key".into()),
        press_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
    module.add(Arc::new("release_keyboard_key".into()),
        release_keyboard_key, PreludeFunction {
            lts: vec![],
            tys: vec![],
            ret: Type::Option(Box::new(Type::F64))
        });
}

pub fn render(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).render_args().is_some() });
    Ok(())
}

pub fn update(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().is_some() });
    Ok(())
}

pub fn press(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).press_args().is_some() });
    Ok(())
}

pub fn release(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).release_args().is_some() });
    Ok(())
}

pub fn focus(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args().is_some() });
    Ok(())
}

pub fn focus_arg(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).focus_args() });
    Ok(())
}

pub fn update_dt(rt: &mut Runtime) -> Result<(), String> {
    rt.push(unsafe { Current::<Option<Event>>::new()
        .as_ref().expect(NO_EVENT).update_args().map(|args| args.dt) });
    Ok(())
}

pub fn press_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.press_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn release_keyboard_key(rt: &mut Runtime) -> Result<(), String> {
    let e = unsafe { &*Current::<Option<Event>>::new() };
    if let &Some(ref e) = e {
        if let Some(Button::Keyboard(key)) = e.release_args() {
            rt.push(Some(key as u64 as f64));
        } else {
            rt.push::<Option<f64>>(None);
        }
        Ok(())
    } else {
        Err(NO_EVENT.into())
    }
}

pub fn set_title<W: Any + AdvancedWindow>(rt: &mut Runtime) -> Result<(), String> {
    use std::sync::Arc;

    let window = unsafe { &mut *Current::<W>::new() };
    let title: Arc<String> = try!(rt.pop());
    window.set_title((*title).clone());
    Ok(())
}

pub fn draw_2d<G: Graphics>(rt: &mut Runtime, c: Context, g: &mut G) -> Result<(), String> {
    use self::graphics::*;

    let draw_list = rt.stack.pop().expect("There is no value on the stack");
    let arr = rt.resolve(&draw_list);
    if let &Variable::Array(ref arr) = arr {
        for it in &**arr {
            let it = rt.resolve(it);
            if let &Variable::Array(ref it) = it {
                let ty: Arc<String> = try!(rt.var(&it[0]));
                match &**ty {
                    "clear" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        clear(color, g);
                    }
                    "line_color_radius_from_to" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let radius: f64 = try!(rt.var(&it[2]));
                        let from: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let to: [f64; 2] = try!(rt.var_vec4(&it[4]));
                        line(color, radius, [from[0], from[1], to[0], to[1]], c.transform, g);
                    }
                    "rectangle_color_corner_size" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        rectangle(color, [corner[0], corner[1], size[0], size[1]], c.transform, g);
                    }
                    "ellipse_color_corner_size_resolution" => {
                        let color: [f32; 4] = try!(rt.var_vec4(&it[1]));
                        let corner: [f64; 2] = try!(rt.var_vec4(&it[2]));
                        let size: [f64; 2] = try!(rt.var_vec4(&it[3]));
                        let resolution: u32 = try!(rt.var(&it[4]));
                        Ellipse::new(color)
                        .resolution(resolution as u32)
                        .draw([corner[0], corner[1], size[0], size[1]], &c.draw_state, c.transform, g);
                    }
                    _ => {}
                }
            }
        }
    }
    return Ok(())
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

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

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

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use cita_types::{clean_0x, Address};
use serde_derive::Deserialize;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
use util::parse_config;

#[derive(Debug, Deserialize, Clone)]
pub struct NetConfig {
    pub port: Option<usize>,
    pub peers: Option<Vec<PeerConfig>>,
    pub max_connects: Option<usize>,
    pub enable_tls: Option<bool>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct PeerConfig {
    pub ip: Option<String>,
    pub port: Option<usize>,
}

impl NetConfig {
    pub fn new(path: &str) -> Self {
        parse_config!(NetConfig, path)
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct AddressConfig {
    pub addr: Address,
}

impl AddressConfig {
    pub fn new(path: &str) -> Self {
        let mut buffer = String::new();
        File::open(path)
            .and_then(|mut f| f.read_to_string(&mut buffer))
            .unwrap_or_else(|err| panic!("[Config] Error while loading node address: [{}]", err));

        let addr = Address::from_str(clean_0x(&buffer)).unwrap();

        AddressConfig { addr }
    }
}

#[cfg(test)]
mod tests {
    use super::NetConfig;
    use std::io::Write;
    use tempfile::NamedTempFile;

    #[test]
    fn basic_test() {
        let toml_str = r#"
        port = 4000
        enable_tls = true
        max_connects = 4
        id_card = 9
        [[peers]]
            ip = "127.0.0.1"
            port = 4001
            common_name = "test1.cita"
        [[peers]]
            ip = "127.0.0.1"
            port = 4002
        "#;

        let mut tmp_file: NamedTempFile = NamedTempFile::new().unwrap();
        tmp_file.write_all(toml_str.as_bytes()).unwrap();
        let path = tmp_file.path().to_str().unwrap();
        let config = NetConfig::new(path);

        assert_eq!(config.port, Some(4000));
        assert_eq!(config.max_connects, Some(4));
        assert_eq!(config.enable_tls, Some(true));
        assert_eq!(config.peers.unwrap().len(), 2);
    }
}
<commit_msg>Do not panic while there is no address file in config path: Using a random address.<commit_after>// CITA
// Copyright 2016-2019 Cryptape Technologies LLC.

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

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

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use cita_types::{clean_0x, Address};
use logger::info;
use serde_derive::Deserialize;
use std::fs::File;
use std::io::Read;
use std::str::FromStr;
use util::parse_config;

#[derive(Debug, Deserialize, Clone)]
pub struct NetConfig {
    pub port: Option<usize>,
    pub peers: Option<Vec<PeerConfig>>,
    pub max_connects: Option<usize>,
    pub enable_tls: Option<bool>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct PeerConfig {
    pub ip: Option<String>,
    pub port: Option<usize>,
}

impl NetConfig {
    pub fn new(path: &str) -> Self {
        parse_config!(NetConfig, path)
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct AddressConfig {
    pub addr: Address,
}

impl AddressConfig {
    pub fn new(path: &str) -> Self {
        let mut buffer = String::new();
        let mut addr = Address::random();
        if let Ok(_sizes) = File::open(path).and_then(|mut f| f.read_to_string(&mut buffer)) {
            addr = Address::from_str(clean_0x(&buffer)).unwrap();
        } else {
            info!("[Config] Cannot find address file, using a random Address instead.");
        }

        AddressConfig { addr }
    }
}

#[cfg(test)]
mod tests {
    use super::NetConfig;
    use std::io::Write;
    use tempfile::NamedTempFile;

    #[test]
    fn basic_test() {
        let toml_str = r#"
        port = 4000
        enable_tls = true
        max_connects = 4
        id_card = 9
        [[peers]]
            ip = "127.0.0.1"
            port = 4001
            common_name = "test1.cita"
        [[peers]]
            ip = "127.0.0.1"
            port = 4002
        "#;

        let mut tmp_file: NamedTempFile = NamedTempFile::new().unwrap();
        tmp_file.write_all(toml_str.as_bytes()).unwrap();
        let path = tmp_file.path().to_str().unwrap();
        let config = NetConfig::new(path);

        assert_eq!(config.port, Some(4000));
        assert_eq!(config.max_connects, Some(4));
        assert_eq!(config.enable_tls, Some(true));
        assert_eq!(config.peers.unwrap().len(), 2);
    }
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::hir::map::Node::NodeItem;
use rustc::lint::*;
use rustc::ty::TypeVariants;
use syntax::ast::LitKind;
use syntax::symbol::InternedString;
use utils::paths;
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty};

/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
///
/// **Why is this bad?** There is no point of doing that. `format!("too")` can
/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
/// is `foo: &str`.
///
/// **Known problems:** None.
///
/// **Examples:**
/// ```rust
/// format!("foo")
/// format!("{}", foo)
/// ```
declare_lint! {
    pub USELESS_FORMAT,
    Warn,
    "useless use of `format!`"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array![USELESS_FORMAT]
    }
}

impl LateLintPass for Pass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let Some(span) = is_expn_of(cx, expr.span, "format") {
            match expr.node {
                // `format!("{}", foo)` expansion
                ExprCall(ref fun, ref args) => {
                    if_let_chain!{[
                        let ExprPath(..) = fun.node,
                        args.len() == 2,
                        let Some(fun) = resolve_node(cx, fun.id),
                        match_def_path(cx, fun.def_id(), &paths::FMT_ARGUMENTS_NEWV1),
                        // ensure the format string is `"{..}"` with only one argument and no text
                        check_static_str(cx, &args[0]),
                        // ensure the format argument is `{}` ie. Display with no fancy option
                        check_arg_is_display(cx, &args[1])
                    ], {
                        span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                    }}
                }
                // `format!("foo")` expansion contains `match () { () => [], }`
                ExprMatch(ref matchee, _, _) => {
                    if let ExprTup(ref tup) = matchee.node {
                        if tup.is_empty() {
                            span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                        }
                    }
                }
                _ => (),
            }
        }
    }
}

/// Returns the slice of format string parts in an `Arguments::new_v1` call.
/// Public because it's shared with a lint in print.rs.
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr)
                                         -> Option<Vec<InternedString>> {
    if_let_chain! {[
        let ExprBlock(ref block) = expr.node,
        block.stmts.len() == 1,
        let StmtDecl(ref decl, _) = block.stmts[0].node,
        let DeclItem(ref decl) = decl.node,
        let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id),
        &*decl.name.as_str() == "__STATIC_FMTSTR",
        let ItemStatic(_, _, ref expr) = decl.node,
        let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
        let ExprArray(ref exprs) = expr.node,
    ], {
        let mut result = Vec::new();
        for expr in exprs {
            if let ExprLit(ref lit) = expr.node {
                if let LitKind::Str(ref lit, _) = lit.node {
                    result.push(lit.as_str());
                }
            }
        }
        return Some(result);
    }}
    None
}

/// Checks if the expressions matches
/// ```rust
/// { static __STATIC_FMTSTR: … = &["…", "…", …]; __STATIC_FMTSTR }
/// ```
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
    if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
        expr.len() == 1 && expr[0].is_empty()
    } else {
        false
    }
}

/// Checks if the expressions matches
/// ```rust
/// &match (&42,) {
///     (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)],
/// })
/// ```
fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
    if_let_chain! {[
        let ExprAddrOf(_, ref expr) = expr.node,
        let ExprMatch(_, ref arms, _) = expr.node,
        arms.len() == 1,
        arms[0].pats.len() == 1,
        let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node,
        pat.len() == 1,
        let ExprArray(ref exprs) = arms[0].body.node,
        exprs.len() == 1,
        let ExprCall(_, ref args) = exprs[0].node,
        args.len() == 2,
        let ExprPath(None, _) = args[1].node,
        let Some(fun) = resolve_node(cx, args[1].id),
        match_def_path(cx, fun.def_id(), &paths::DISPLAY_FMT_METHOD),
    ], {
        let ty = walk_ptrs_ty(cx.tcx.tables().pat_ty(&pat[0]));

        return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING);
    }}

    false
}
<commit_msg>useless_format: fix typo<commit_after>use rustc::hir::*;
use rustc::hir::map::Node::NodeItem;
use rustc::lint::*;
use rustc::ty::TypeVariants;
use syntax::ast::LitKind;
use syntax::symbol::InternedString;
use utils::paths;
use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty};

/// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string.
///
/// **Why is this bad?** There is no point of doing that. `format!("too")` can
/// be replaced by `"foo".to_owned()` if you really need a `String`. The even
/// worse `&format!("foo")` is often encountered in the wild. `format!("{}",
/// foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
/// if `foo: &str`.
///
/// **Known problems:** None.
///
/// **Examples:**
/// ```rust
/// format!("foo")
/// format!("{}", foo)
/// ```
declare_lint! {
    pub USELESS_FORMAT,
    Warn,
    "useless use of `format!`"
}

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

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array![USELESS_FORMAT]
    }
}

impl LateLintPass for Pass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let Some(span) = is_expn_of(cx, expr.span, "format") {
            match expr.node {
                // `format!("{}", foo)` expansion
                ExprCall(ref fun, ref args) => {
                    if_let_chain!{[
                        let ExprPath(..) = fun.node,
                        args.len() == 2,
                        let Some(fun) = resolve_node(cx, fun.id),
                        match_def_path(cx, fun.def_id(), &paths::FMT_ARGUMENTS_NEWV1),
                        // ensure the format string is `"{..}"` with only one argument and no text
                        check_static_str(cx, &args[0]),
                        // ensure the format argument is `{}` ie. Display with no fancy option
                        check_arg_is_display(cx, &args[1])
                    ], {
                        span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                    }}
                }
                // `format!("foo")` expansion contains `match () { () => [], }`
                ExprMatch(ref matchee, _, _) => {
                    if let ExprTup(ref tup) = matchee.node {
                        if tup.is_empty() {
                            span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`");
                        }
                    }
                }
                _ => (),
            }
        }
    }
}

/// Returns the slice of format string parts in an `Arguments::new_v1` call.
/// Public because it's shared with a lint in print.rs.
pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr)
                                         -> Option<Vec<InternedString>> {
    if_let_chain! {[
        let ExprBlock(ref block) = expr.node,
        block.stmts.len() == 1,
        let StmtDecl(ref decl, _) = block.stmts[0].node,
        let DeclItem(ref decl) = decl.node,
        let Some(NodeItem(decl)) = cx.tcx.map.find(decl.id),
        &*decl.name.as_str() == "__STATIC_FMTSTR",
        let ItemStatic(_, _, ref expr) = decl.node,
        let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …]
        let ExprArray(ref exprs) = expr.node,
    ], {
        let mut result = Vec::new();
        for expr in exprs {
            if let ExprLit(ref lit) = expr.node {
                if let LitKind::Str(ref lit, _) = lit.node {
                    result.push(lit.as_str());
                }
            }
        }
        return Some(result);
    }}
    None
}

/// Checks if the expressions matches
/// ```rust
/// { static __STATIC_FMTSTR: … = &["…", "…", …]; __STATIC_FMTSTR }
/// ```
fn check_static_str(cx: &LateContext, expr: &Expr) -> bool {
    if let Some(expr) = get_argument_fmtstr_parts(cx, expr) {
        expr.len() == 1 && expr[0].is_empty()
    } else {
        false
    }
}

/// Checks if the expressions matches
/// ```rust
/// &match (&42,) {
///     (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Display::fmt)],
/// })
/// ```
fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
    if_let_chain! {[
        let ExprAddrOf(_, ref expr) = expr.node,
        let ExprMatch(_, ref arms, _) = expr.node,
        arms.len() == 1,
        arms[0].pats.len() == 1,
        let PatKind::Tuple(ref pat, None) = arms[0].pats[0].node,
        pat.len() == 1,
        let ExprArray(ref exprs) = arms[0].body.node,
        exprs.len() == 1,
        let ExprCall(_, ref args) = exprs[0].node,
        args.len() == 2,
        let ExprPath(None, _) = args[1].node,
        let Some(fun) = resolve_node(cx, args[1].id),
        match_def_path(cx, fun.def_id(), &paths::DISPLAY_FMT_METHOD),
    ], {
        let ty = walk_ptrs_ty(cx.tcx.tables().pat_ty(&pat[0]));

        return ty.sty == TypeVariants::TyStr || match_type(cx, ty, &paths::STRING);
    }}

    false
}
<|endoftext|>