<commit_before>mod page;
pub use self::page::Page;

use std::env;
use std::io::Read;
use std::ascii::AsciiExt;
use std::default::Default;
use std::collections::BTreeMap;

use url::Url;
use reqwest::Client as HttpClient;
use reqwest::header::{Headers, UserAgent};
use reqwest::StatusCode;
use reqwest::Response as HttpResponse;
use robotparser::RobotFileParser;
use html5ever::tokenizer::Tokenizer;
use html5ever::tokenizer::buffer_queue::BufferQueue;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_8;
use url_serde::Serde;

const MAMAN_ENV: &str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(redis_pool: RedisPool, base_url: Url, limit: isize) -> Spider<'a> {
        let maman_env =
            env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts { namespace: Some(maman_env.to_string()) };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url: base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq: sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit: limit,
        }
    }

    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in &page.urls {
            self.unvisited_urls.push(u.clone());
        }
        if let Err(err) = self.sidekiq.push(page.to_job()) {
            error!("SidekiqClient push failed: {}", err);
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref()) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref()) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser
            .can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers().iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = vec![];
        let _ = response.read_to_end(&mut document);
        match UTF_8.decode(&document, DecoderTrap::Ignore) {
            Ok(doc) => {
                let page = Page::new(page_url.clone(),
                                     doc.to_string(),
                                     headers.clone(),
                                     response.status().to_string());
                let read = Spider::read_page(page, &doc).unwrap();
                Some(read)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str) -> Option<HttpResponse> {
        let client = HttpClient::new().expect("HttpClient failed to construct");
        let mut headers = Headers::new();
        headers.set(UserAgent::new(maman_user_agent!().to_owned()));
        match client.get(url) {
            Err(_) => None,
            Ok(mut request) => {
                request.headers(headers);
                match request.send() {
                    Ok(response) => {
                        match response.status() {
                            StatusCode::Ok | StatusCode::NotModified => Some(response),
                            _ => None,
                        }
                    }
                    Err(_) => None,
                }
            }
        }
    }
}
<commit_msg>Fix clippy warnings<commit_after>mod page;
pub use self::page::Page;

use std::env;
use std::io::Read;
#[allow(unused_imports)]
use std::ascii::AsciiExt;
use std::default::Default;
use std::collections::BTreeMap;

use url::Url;
use reqwest::Client as HttpClient;
use reqwest::header::{Headers, UserAgent};
use reqwest::StatusCode;
use reqwest::Response as HttpResponse;
use robotparser::RobotFileParser;
use html5ever::tokenizer::Tokenizer;
use html5ever::tokenizer::buffer_queue::BufferQueue;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use encoding::{Encoding, DecoderTrap};
use encoding::all::UTF_8;
use url_serde::Serde;

const MAMAN_ENV: &str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(redis_pool: RedisPool, base_url: Url, limit: isize) -> Spider<'a> {
        let maman_env =
            env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts { namespace: Some(maman_env.to_string()) };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url: base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq: sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit: limit,
        }
    }

    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in &page.urls {
            self.unvisited_urls.push(u.clone());
        }
        if let Err(err) = self.sidekiq.push(page.to_job()) {
            error!("SidekiqClient push failed: {}", err);
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref()) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref()) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser
            .can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for h in response.headers().iter() {
                headers.insert(h.name().to_ascii_lowercase(), h.value_string());
            }
        }
        let mut document = vec![];
        let _ = response.read_to_end(&mut document);
        match UTF_8.decode(&document, DecoderTrap::Ignore) {
            Ok(doc) => {
                let page = Page::new(page_url.clone(),
                                     doc.to_string(),
                                     headers.clone(),
                                     response.status().to_string());
                let read = Spider::read_page(page, &doc).unwrap();
                Some(read)
            }
            Err(_) => None,
        }
    }

    fn load_url(url: &str) -> Option<HttpResponse> {
        let client = HttpClient::new().expect("HttpClient failed to construct");
        let mut headers = Headers::new();
        headers.set(UserAgent::new(maman_user_agent!().to_owned()));
        match client.get(url) {
            Err(_) => None,
            Ok(mut request) => {
                request.headers(headers);
                match request.send() {
                    Ok(response) => {
                        match response.status() {
                            StatusCode::Ok | StatusCode::NotModified => Some(response),
                            _ => None,
                        }
                    }
                    Err(_) => None,
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::f32::consts::{
  PI,
  FRAC_PI_2
};
use std::num::{
  sqrt,
  pow,
  sin,
  cos
};
use glfw;
use gl;
use std;
use gl::types::{
  GLfloat,
  GLint,
  GLuint
};
use cgmath::matrix::{
  Matrix
};
use cgmath::vector::{
  Vec3,
  Vec2,
  Vector
};
use glh = gl_helpers;
use camera::Camera;
use glfw_events::EventHandlers;
use map::TileIterator;

static WIN_SIZE: Vec2<u32> = Vec2{x: 640, y: 480};

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 mvp_mat;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = mvp_mat * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

static PICK_VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  in vec3 color;
  out vec3 pass_color;
  uniform mat4 mvp_mat;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = mvp_mat * v;
    pass_color = color;
  }
";

static PICK_FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  in vec3 pass_color;
  out vec4 out_color;
  void main() {
    out_color = vec4(pass_color, 1.0);
  }
";

struct TilePicker {
  program: GLuint,
  color_buffer_obj: GLuint,
  mat_id: GLint,
  vertex_buffer_obj: GLuint,
  vertex_data: ~[Vec3<GLfloat>],
  color_data: ~[Vec3<GLfloat>],
  selected_tile_pos: Option<Vec2<int>>
}

impl TilePicker {
  fn new() -> TilePicker {
    TilePicker {
      color_buffer_obj: 0,
      program: 0,
      vertex_buffer_obj: 0,
      mat_id: 0,
      vertex_data: ~[],
      color_data: ~[],
      selected_tile_pos: None
    }
  }

  fn init_opengl(&mut self) {
    self.program = glh::compile_program(
      PICK_VERTEX_SHADER_SRC,
      PICK_FRAGMENT_SHADER_SRC);
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteBuffers(1, &self.color_buffer_obj);
    }
  }
}

impl Drop for TilePicker {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

pub struct Visualizer {
  hex_ex_radius: GLfloat,
  hex_in_radius: GLfloat,
  glfw_event_handlers: EventHandlers,
  program: GLuint,
  vertex_buffer_obj: GLuint,
  mat_id: GLint,
  win: Option<glfw::Window>,
  vertex_data: ~[Vec3<GLfloat>],
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker
}

fn init_win() -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  glfw::init();
  let win = glfw::Window::create(
    WIN_SIZE.x,
    WIN_SIZE.y,
    "OpenGL",
    glfw::Windowed
  ).unwrap();
  win.make_context_current();
  win
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let hex_ex_radius: GLfloat = 1.0 / 2.0;
    let hex_in_radius = sqrt(
        pow(hex_ex_radius, 2) - pow(hex_ex_radius / 2.0, 2));
    let win = init_win();
    let mut vis = ~Visualizer {
      hex_ex_radius: hex_ex_radius,
      hex_in_radius: hex_in_radius,
      glfw_event_handlers: EventHandlers::new(&win),
      program: 0,
      vertex_buffer_obj: 0,
      mat_id: 0,
      win: Some(win),
      vertex_data: ~[],
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new()
    };
    vis.init_opengl();
    vis.init_model();
    vis.init_tile_picker();
    vis
  }

  pub fn v2i_to_v2f(&self, i: Vec2<i32>) -> Vec2<f32> {
    let v = Vec2 {
      x: (i.x as f32) * self.hex_in_radius * 2.0,
      y: (i.y as f32) * self.hex_ex_radius * 1.5
    };
    if i.y % 2 == 0 {
      Vec2{x: v.x + self.hex_in_radius, y: v.y}
    } else {
      v
    }
  }

  pub fn index_to_circle_vertex(&self, count: int, i: int) -> Vec2<f32> {
    let n = FRAC_PI_2 + 2.0 * PI * (i as f32) / (count as f32);
    Vec2{x: cos(n), y: sin(n)}.mul_s(self.hex_ex_radius)
  }

  pub fn index_to_hex_vertex(&self, i: int) -> Vec2<f32> {
    self.index_to_circle_vertex(6, i)
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn build_hex_mesh(&mut self) {
    for tile_pos in TileIterator::new() {
      let pos3d = self.v2i_to_v2f(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = self.index_to_hex_vertex(num);
        let next_vertex = self.index_to_hex_vertex(num + 1);
        let data = &mut self.vertex_data;
        data.push(pos3d + vertex.extend(0.0));
        data.push(pos3d + next_vertex.extend(0.0));
        data.push(pos3d + Vec3::zero());
      }
    }
  }

  fn init_model(&mut self) {
    self.build_hex_mesh();
    unsafe {
      gl::UseProgram(self.program);
      gl::GenBuffers(1, &mut self.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
      glh::fill_current_coord_vbo(self.vertex_data);
      let pos_attr = glh::get_attr(self.program, "position");
      gl::EnableVertexAttribArray(pos_attr);
      glh::define_array_of_generic_attr_data(pos_attr);
      self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    }
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
    self.program = glh::compile_program(
      VERTEX_SHADER_SRC,
      FRAGMENT_SHADER_SRC);
    self.picker.init_opengl();
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
    }
    self.picker.cleanup_opengl();
  }

  fn draw_map(&self) {
    gl::UseProgram(self.program);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    glh::draw_mesh(self.vertex_data);
  }

  pub fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  pub fn handle_key_events(&mut self) {
    self.glfw_event_handlers.key_handler.handle(|event| {
      if event.action != glfw::Press {
        return;
      }
      match event.key {
        glfw::KeyEscape | glfw::KeyQ
                       => self.win().set_should_close(true),
        glfw::KeySpace => println!("space"),
        glfw::KeyUp    => self.camera.move(270.0),
        glfw::KeyDown  => self.camera.move(90.0),
        glfw::KeyRight => self.camera.move(0.0),
        glfw::KeyLeft  => self.camera.move(180.0),
        _ => {}
      }
    });
  }

  pub fn handle_cursor_pos_events(&mut self) {
    self.glfw_event_handlers.cursor_pos_handler.handle(|event| {
      let button = self.win().get_mouse_button(glfw::MouseButtonRight);
      if button == glfw::Press {
        self.camera.z_angle += self.mouse_pos.x - event.x;
        self.camera.x_angle += self.mouse_pos.y - event.y;
      }
      self.mouse_pos = Vec2{x: event.x, y: event.y};
    });
  }

  pub fn handle_events(&mut self) {
    glfw::poll_events();
    self.handle_key_events();
    self.handle_cursor_pos_events();
  }

  fn close_window(&mut self) {
    // destroy glfw::Window before terminating glfw
    self.win = None;
  }

  fn build_hex_mesh_for_picking(&mut self) {
    for tile_pos in TileIterator::new() {
      let pos3d = self.v2i_to_v2f(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = self.index_to_hex_vertex(num);
        let next_vertex = self.index_to_hex_vertex(num + 1);
        let col_x = tile_pos.x as f32 / 255.0;
        let col_y = tile_pos.y as f32 / 255.0;
        let c_data = &mut self.picker.color_data;
        let v_data = &mut self.picker.vertex_data;
        let color = Vec3{x: col_x, y: col_y, z: 1.0};
        v_data.push(pos3d + vertex.extend(0.0));
        c_data.push(color);
        v_data.push(pos3d + next_vertex.extend(0.0));
        c_data.push(color);
        v_data.push(pos3d + Vec3::zero());
        c_data.push(color);
      }
    }
  }

  fn init_tile_picker(&mut self) {
    self.build_hex_mesh_for_picking();
    unsafe {
      gl::UseProgram(self.picker.program);
      gl::GenBuffers(1, &mut self.picker.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.vertex_buffer_obj);
      glh::fill_current_coord_vbo(self.picker.vertex_data);
      let pos_attr = glh::get_attr(self.picker.program, "position");
      gl::EnableVertexAttribArray(pos_attr);
      glh::define_array_of_generic_attr_data(pos_attr);
      gl::GenBuffers(1, &mut self.picker.color_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.color_buffer_obj);
      glh::fill_current_color_vbo(self.picker.color_data);
      let color_attr = glh::get_attr(self.picker.program, "color");
      gl::EnableVertexAttribArray(color_attr);
      glh::define_array_of_generic_attr_data(color_attr);
      self.picker.mat_id = glh::get_uniform(self.picker.program, "mvp_mat");
    }
  }

  fn _pick_tile(&self, x: i32, y: i32) -> Option<Vec2<int>> {
    let (_, height) = self.win().get_size();
    let reverted_y = height - y;
    let data: [u8, ..4] = [0, 0, 0, 0]; // mut
    unsafe {
      let data_ptr = std::cast::transmute(&data[0]);
      gl::ReadPixels(
        x, reverted_y, 1, 1,
        gl::RGBA,
        gl::UNSIGNED_BYTE,
        data_ptr
      );
    }
    if data[2] != 0 {
      Some(Vec2{x: data[0] as int, y: data[1] as int})
    } else {
      None
    }
  }

  pub fn pick_tile(&mut self) {
    gl::UseProgram(self.picker.program);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.vertex_buffer_obj);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.color_buffer_obj);
    glh::uniform_mat4f(self.picker.mat_id, &self.camera.mat());
    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    glh::draw_mesh(self.picker.vertex_data);
    self.picker.selected_tile_pos = self._pick_tile(
      self.mouse_pos.x as i32,
      self.mouse_pos.y as i32
    );
    println!("selected: {:?}", self.picker.selected_tile_pos);
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
    self.close_window();
    glfw::terminate();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Visualizer: Moved WIN_SIZE to new()<commit_after>// See LICENSE file for copyright and license details.

use std::f32::consts::{
  PI,
  FRAC_PI_2
};
use std::num::{
  sqrt,
  pow,
  sin,
  cos
};
use glfw;
use gl;
use std;
use gl::types::{
  GLfloat,
  GLint,
  GLuint
};
use cgmath::matrix::{
  Matrix
};
use cgmath::vector::{
  Vec3,
  Vec2,
  Vector
};
use glh = gl_helpers;
use camera::Camera;
use glfw_events::EventHandlers;
use map::TileIterator;

static VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  uniform mat4 mvp_mat;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = mvp_mat * v;
  }
";

static FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  out vec4 out_color;
  void main() {
    out_color = vec4(1.0, 1.0, 1.0, 1.0);
  }
";

static PICK_VERTEX_SHADER_SRC: &'static str = "
  #version 130
  in vec3 position;
  in vec3 color;
  out vec3 pass_color;
  uniform mat4 mvp_mat;
  void main() {
    vec4 v = vec4(position, 1);
    gl_Position = mvp_mat * v;
    pass_color = color;
  }
";

static PICK_FRAGMENT_SHADER_SRC: &'static str = "
  #version 130
  in vec3 pass_color;
  out vec4 out_color;
  void main() {
    out_color = vec4(pass_color, 1.0);
  }
";

struct TilePicker {
  program: GLuint,
  color_buffer_obj: GLuint,
  mat_id: GLint,
  vertex_buffer_obj: GLuint,
  vertex_data: ~[Vec3<GLfloat>],
  color_data: ~[Vec3<GLfloat>],
  selected_tile_pos: Option<Vec2<int>>
}

impl TilePicker {
  fn new() -> TilePicker {
    TilePicker {
      color_buffer_obj: 0,
      program: 0,
      vertex_buffer_obj: 0,
      mat_id: 0,
      vertex_data: ~[],
      color_data: ~[],
      selected_tile_pos: None
    }
  }

  fn init_opengl(&mut self) {
    self.program = glh::compile_program(
      PICK_VERTEX_SHADER_SRC,
      PICK_FRAGMENT_SHADER_SRC);
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
      gl::DeleteBuffers(1, &self.color_buffer_obj);
    }
  }
}

impl Drop for TilePicker {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

pub struct Visualizer {
  hex_ex_radius: GLfloat,
  hex_in_radius: GLfloat,
  glfw_event_handlers: EventHandlers,
  program: GLuint,
  vertex_buffer_obj: GLuint,
  mat_id: GLint,
  win: Option<glfw::Window>,
  vertex_data: ~[Vec3<GLfloat>],
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  glfw::init();
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "OpenGL",
    glfw::Windowed
  ).unwrap();
  win.make_context_current();
  win
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let hex_ex_radius: GLfloat = 1.0 / 2.0;
    let hex_in_radius = sqrt(
        pow(hex_ex_radius, 2) - pow(hex_ex_radius / 2.0, 2));
    let win_size = Vec2::<int>{x: 640, y: 480};
    let win = init_win(win_size);
    let mut vis = ~Visualizer {
      hex_ex_radius: hex_ex_radius,
      hex_in_radius: hex_in_radius,
      glfw_event_handlers: EventHandlers::new(&win),
      program: 0,
      vertex_buffer_obj: 0,
      mat_id: 0,
      win: Some(win),
      vertex_data: ~[],
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new()
    };
    vis.init_opengl();
    vis.init_model();
    vis.init_tile_picker();
    vis
  }

  pub fn v2i_to_v2f(&self, i: Vec2<i32>) -> Vec2<f32> {
    let v = Vec2 {
      x: (i.x as f32) * self.hex_in_radius * 2.0,
      y: (i.y as f32) * self.hex_ex_radius * 1.5
    };
    if i.y % 2 == 0 {
      Vec2{x: v.x + self.hex_in_radius, y: v.y}
    } else {
      v
    }
  }

  pub fn index_to_circle_vertex(&self, count: int, i: int) -> Vec2<f32> {
    let n = FRAC_PI_2 + 2.0 * PI * (i as f32) / (count as f32);
    Vec2{x: cos(n), y: sin(n)}.mul_s(self.hex_ex_radius)
  }

  pub fn index_to_hex_vertex(&self, i: int) -> Vec2<f32> {
    self.index_to_circle_vertex(6, i)
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn build_hex_mesh(&mut self) {
    for tile_pos in TileIterator::new() {
      let pos3d = self.v2i_to_v2f(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = self.index_to_hex_vertex(num);
        let next_vertex = self.index_to_hex_vertex(num + 1);
        let data = &mut self.vertex_data;
        data.push(pos3d + vertex.extend(0.0));
        data.push(pos3d + next_vertex.extend(0.0));
        data.push(pos3d + Vec3::zero());
      }
    }
  }

  fn init_model(&mut self) {
    self.build_hex_mesh();
    unsafe {
      gl::UseProgram(self.program);
      gl::GenBuffers(1, &mut self.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
      glh::fill_current_coord_vbo(self.vertex_data);
      let pos_attr = glh::get_attr(self.program, "position");
      gl::EnableVertexAttribArray(pos_attr);
      glh::define_array_of_generic_attr_data(pos_attr);
      self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    }
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
    self.program = glh::compile_program(
      VERTEX_SHADER_SRC,
      FRAGMENT_SHADER_SRC);
    self.picker.init_opengl();
  }

  pub fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
    unsafe {
      gl::DeleteBuffers(1, &self.vertex_buffer_obj);
    }
    self.picker.cleanup_opengl();
  }

  fn draw_map(&self) {
    gl::UseProgram(self.program);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.vertex_buffer_obj);
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    glh::draw_mesh(self.vertex_data);
  }

  pub fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  pub fn handle_key_events(&mut self) {
    self.glfw_event_handlers.key_handler.handle(|event| {
      if event.action != glfw::Press {
        return;
      }
      match event.key {
        glfw::KeyEscape | glfw::KeyQ
                       => self.win().set_should_close(true),
        glfw::KeySpace => println!("space"),
        glfw::KeyUp    => self.camera.move(270.0),
        glfw::KeyDown  => self.camera.move(90.0),
        glfw::KeyRight => self.camera.move(0.0),
        glfw::KeyLeft  => self.camera.move(180.0),
        _ => {}
      }
    });
  }

  pub fn handle_cursor_pos_events(&mut self) {
    self.glfw_event_handlers.cursor_pos_handler.handle(|event| {
      let button = self.win().get_mouse_button(glfw::MouseButtonRight);
      if button == glfw::Press {
        self.camera.z_angle += self.mouse_pos.x - event.x;
        self.camera.x_angle += self.mouse_pos.y - event.y;
      }
      self.mouse_pos = Vec2{x: event.x, y: event.y};
    });
  }

  pub fn handle_events(&mut self) {
    glfw::poll_events();
    self.handle_key_events();
    self.handle_cursor_pos_events();
  }

  fn close_window(&mut self) {
    // destroy glfw::Window before terminating glfw
    self.win = None;
  }

  fn build_hex_mesh_for_picking(&mut self) {
    for tile_pos in TileIterator::new() {
      let pos3d = self.v2i_to_v2f(tile_pos).extend(0.0);
      for num in range(0, 6) {
        let vertex = self.index_to_hex_vertex(num);
        let next_vertex = self.index_to_hex_vertex(num + 1);
        let col_x = tile_pos.x as f32 / 255.0;
        let col_y = tile_pos.y as f32 / 255.0;
        let c_data = &mut self.picker.color_data;
        let v_data = &mut self.picker.vertex_data;
        let color = Vec3{x: col_x, y: col_y, z: 1.0};
        v_data.push(pos3d + vertex.extend(0.0));
        c_data.push(color);
        v_data.push(pos3d + next_vertex.extend(0.0));
        c_data.push(color);
        v_data.push(pos3d + Vec3::zero());
        c_data.push(color);
      }
    }
  }

  fn init_tile_picker(&mut self) {
    self.build_hex_mesh_for_picking();
    unsafe {
      gl::UseProgram(self.picker.program);
      gl::GenBuffers(1, &mut self.picker.vertex_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.vertex_buffer_obj);
      glh::fill_current_coord_vbo(self.picker.vertex_data);
      let pos_attr = glh::get_attr(self.picker.program, "position");
      gl::EnableVertexAttribArray(pos_attr);
      glh::define_array_of_generic_attr_data(pos_attr);
      gl::GenBuffers(1, &mut self.picker.color_buffer_obj);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.color_buffer_obj);
      glh::fill_current_color_vbo(self.picker.color_data);
      let color_attr = glh::get_attr(self.picker.program, "color");
      gl::EnableVertexAttribArray(color_attr);
      glh::define_array_of_generic_attr_data(color_attr);
      self.picker.mat_id = glh::get_uniform(self.picker.program, "mvp_mat");
    }
  }

  fn _pick_tile(&self, x: i32, y: i32) -> Option<Vec2<int>> {
    let (_, height) = self.win().get_size();
    let reverted_y = height - y;
    let data: [u8, ..4] = [0, 0, 0, 0]; // mut
    unsafe {
      let data_ptr = std::cast::transmute(&data[0]);
      gl::ReadPixels(
        x, reverted_y, 1, 1,
        gl::RGBA,
        gl::UNSIGNED_BYTE,
        data_ptr
      );
    }
    if data[2] != 0 {
      Some(Vec2{x: data[0] as int, y: data[1] as int})
    } else {
      None
    }
  }

  pub fn pick_tile(&mut self) {
    gl::UseProgram(self.picker.program);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.vertex_buffer_obj);
    gl::BindBuffer(gl::ARRAY_BUFFER, self.picker.color_buffer_obj);
    glh::uniform_mat4f(self.picker.mat_id, &self.camera.mat());
    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    glh::draw_mesh(self.picker.vertex_data);
    self.picker.selected_tile_pos = self._pick_tile(
      self.mouse_pos.x as i32,
      self.mouse_pos.y as i32
    );
    println!("selected: {:?}", self.picker.selected_tile_pos);
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
    self.close_window();
    glfw::terminate();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast::ast::{Item, ItemKind, Variant, VisibilityKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::Ident;

declare_clippy_lint! {
    /// **What it does:** Checks for fully capitalized names and optionally names containing a capitalized acronym.
    ///
    /// **Why is this bad?** In CamelCase, acronyms count as one word.
    /// See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
    /// for more.
    ///
    /// By default, the lint only triggers on fully-capitalized names.
    /// You can use the `upper-case-acronyms-aggressive: true` config option to enable linting
    /// on all camel case names
    ///
    /// **Known problems:** When two acronyms are contiguous, the lint can't tell where
    /// the first acronym ends and the second starts, so it suggests to lowercase all of
    /// the letters in the second acronym.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// struct HTTPResponse;
    /// ```
    /// Use instead:
    /// ```rust
    /// struct HttpResponse;
    /// ```
    pub UPPER_CASE_ACRONYMS,
    style,
    "capitalized acronyms are against the naming convention"
}

#[derive(Default)]
pub struct UpperCaseAcronyms {
    upper_case_acronyms_aggressive: bool,
}

impl UpperCaseAcronyms {
    pub fn new(aggressive: bool) -> Self {
        Self {
            upper_case_acronyms_aggressive: aggressive,
        }
    }
}

impl_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]);

fn correct_ident(ident: &str) -> String {
    let ident = ident.chars().rev().collect::<String>();
    let fragments = ident
        .split_inclusive(|x: char| !x.is_ascii_lowercase())
        .rev()
        .map(|x| x.chars().rev().collect::<String>());

    let mut ident = fragments.clone().next().unwrap();
    for (ref prev, ref curr) in fragments.tuple_windows() {
        if [prev, curr]
            .iter()
            .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
        {
            ident.push_str(&curr.to_ascii_lowercase());
        } else {
            ident.push_str(curr);
        }
    }
    ident
}

fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
    let span = ident.span;
    let ident = &ident.as_str();
    let corrected = correct_ident(ident);
    // warn if we have pure-uppercase idents
    // assume that two-letter words are some kind of valid abbreviation like FP for false positive
    // (and don't warn)
    if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2)
    // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive
    // upper-case-acronyms-aggressive config option enabled
    || (be_aggressive && ident != &corrected)
    {
        span_lint_and_sugg(
            cx,
            UPPER_CASE_ACRONYMS,
            span,
            &format!("name `{}` contains a capitalized acronym", ident),
            "consider making the acronym lowercase, except the initial letter",
            corrected,
            Applicability::MaybeIncorrect,
        )
    }
}

impl EarlyLintPass for UpperCaseAcronyms {
    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
        if_chain! {
            if !in_external_macro(cx.sess(), it.span);
            if matches!(
                it.kind,
                ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
            );
            // do not lint public items
            if !matches!(it.vis.kind, VisibilityKind::Public);
            then {
                check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
            }
        }
    }

    fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &Variant) {
        check_ident(cx, &v.ident, self.upper_case_acronyms_aggressive);
    }
}
<commit_msg>upper_case_acronyms: only lint enum variants if the enum is not public<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast::ast::{Item, ItemKind, Variant, VisibilityKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::Ident;

declare_clippy_lint! {
    /// **What it does:** Checks for fully capitalized names and optionally names containing a capitalized acronym.
    ///
    /// **Why is this bad?** In CamelCase, acronyms count as one word.
    /// See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
    /// for more.
    ///
    /// By default, the lint only triggers on fully-capitalized names.
    /// You can use the `upper-case-acronyms-aggressive: true` config option to enable linting
    /// on all camel case names
    ///
    /// **Known problems:** When two acronyms are contiguous, the lint can't tell where
    /// the first acronym ends and the second starts, so it suggests to lowercase all of
    /// the letters in the second acronym.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// struct HTTPResponse;
    /// ```
    /// Use instead:
    /// ```rust
    /// struct HttpResponse;
    /// ```
    pub UPPER_CASE_ACRONYMS,
    style,
    "capitalized acronyms are against the naming convention"
}

#[derive(Default)]
pub struct UpperCaseAcronyms {
    upper_case_acronyms_aggressive: bool,
}

impl UpperCaseAcronyms {
    pub fn new(aggressive: bool) -> Self {
        Self {
            upper_case_acronyms_aggressive: aggressive,
        }
    }
}

impl_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]);

fn correct_ident(ident: &str) -> String {
    let ident = ident.chars().rev().collect::<String>();
    let fragments = ident
        .split_inclusive(|x: char| !x.is_ascii_lowercase())
        .rev()
        .map(|x| x.chars().rev().collect::<String>());

    let mut ident = fragments.clone().next().unwrap();
    for (ref prev, ref curr) in fragments.tuple_windows() {
        if [prev, curr]
            .iter()
            .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
        {
            ident.push_str(&curr.to_ascii_lowercase());
        } else {
            ident.push_str(curr);
        }
    }
    ident
}

fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
    let span = ident.span;
    let ident = &ident.as_str();
    let corrected = correct_ident(ident);
    // warn if we have pure-uppercase idents
    // assume that two-letter words are some kind of valid abbreviation like FP for false positive
    // (and don't warn)
    if (ident.chars().all(|c| c.is_ascii_uppercase()) && ident.len() > 2)
    // otherwise, warn if we have SOmeTHING lIKE THIs but only warn with the aggressive
    // upper-case-acronyms-aggressive config option enabled
    || (be_aggressive && ident != &corrected)
    {
        span_lint_and_sugg(
            cx,
            UPPER_CASE_ACRONYMS,
            span,
            &format!("name `{}` contains a capitalized acronym", ident),
            "consider making the acronym lowercase, except the initial letter",
            corrected,
            Applicability::MaybeIncorrect,
        )
    }
}

impl EarlyLintPass for UpperCaseAcronyms {
    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
        // do not lint public items or in macros
        if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
            if matches!(
                it.kind,
                ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
            ) {
                check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
            } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
                // check enum variants seperately because again we only want to lint on private enums and
                // the fn check_variant does not know about the vis of the enum of its variants
                &enumdef
                    .variants
                    .iter()
                    .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
#[macro_use]
extern crate nickel;
extern crate redis;
extern crate r2d2;
extern crate r2d2_redis;
extern crate plugin;
extern crate typemap;

extern crate core;

use std::env;
use std::collections::HashMap;
use r2d2::NopErrorHandler;
use nickel::{Nickel, HttpRouter, JsonBody, MediaType, QueryString};
use nickel::status::StatusCode;
use core::ops::Deref;
use redis::{Commands, Connection};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;

use redis_middleware::{RedisMiddleware, RedisRequestExtensions};
mod redis_middleware;

#[derive(RustcDecodable, RustcEncodable)]
struct RatingSubmission {
    uuid: String,
    mod_str: String,
    rating: Rating,
}

#[derive(Clone, Copy, Debug)]
enum Rating {
    Poor = 0,
    BelowAverage,
    Average,
    AboveAverage,
    Excellent,
}

#[derive(RustcEncodable)]
struct RatingResults {
    average: HashMap<String, Rating>,
    own: Option<HashMap<String, Rating>>,
}

impl From<u8> for Rating {
    fn from(rating: u8) -> Self {
        match rating {
            0 => Rating::Poor,
            1 => Rating::BelowAverage,
            2 => Rating::Average,
            3 => Rating::AboveAverage,
            _ => Rating::Excellent,
        }
    }
}

impl Decodable for Rating {
    fn decode<D: Decoder>(d: &mut D) -> Result<Rating, D::Error> {
        let r = try!(d.read_u8());
        Ok(Rating::from(r))
    }
}

impl Encodable for Rating {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let as_u8 = *self as u8;
        s.emit_u8(as_u8)
    }
}

fn incr_requests(conn: &Connection) {
    if let Err(_) = conn.incr::<_, _, u64>("requests", 1) {
        println!("failed to incr request counter.")
    }
}

const OK_RESP: (StatusCode, &'static str) = (StatusCode::Ok, "ok");

fn main() {
    let mut webserver = Nickel::new();

    let redis_url = env::var("DATABASE_URL").unwrap_or("redis://localhost/3".to_owned());
    println!("connecting to redis @ {}", redis_url);

    let redispool = RedisMiddleware::new(&*redis_url, 3, Box::new(NopErrorHandler)).unwrap();
    webserver.utilize(redispool);

    webserver.post("/submit",
                   middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let sbm = try_with!(response, {
            request.json_as::<RatingSubmission>().map_err(|e| (StatusCode::BadRequest, e))
        });
        println!("{} rates {} as {:?}", sbm.uuid, sbm.mod_str, sbm.rating);
        let _: u8 = try_with!(response, {
            redis_conn.hset(sbm.mod_str, sbm.uuid, sbm.rating as u8).map_err(|e|
                (StatusCode::BadRequest, e)
            )
        });
        OK_RESP
    });

    webserver.get("/rating/:mod",
                  middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let mod_str = request.param("mod").unwrap();
        let ratings = try_with!(response, {
            redis_conn.hvals::<_, Vec<u8>>(mod_str).map_err(|e| (StatusCode::BadRequest, e))
        });
        let length = ratings.len();
        let mut sum = 0usize;
        for rating in ratings {
            sum += rating as usize;
        }
        match length {
            0 => (StatusCode::NotFound, "{\"not_found\": true}".to_owned()),
            _ => (StatusCode::Ok, format!("{}", sum / length)),
        }
    });

    webserver.get("/ratings",
                  middleware! { |request, mut response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);

        let mods = try_with!(response, {
            redis_conn.hkeys::<_, Vec<String>>("mods").map_err(|e| (StatusCode::BadRequest, e))
        });

        let mut own_ratings = HashMap::new();
        let mut average_ratings = HashMap::new();

        for mod_str in mods {
            let mod_str = mod_str.as_str();
            let ratings = try_with!(response, {
                redis_conn.hvals::<_, Vec<u8>>(mod_str).map_err(|e| (StatusCode::BadRequest, e))
            });
            let length = ratings.len();
            let mut sum = 0usize;
            for rating in ratings {
                sum += rating as usize;
            }
            if length > 0 {
                average_ratings.insert(mod_str.to_owned(), Rating::from((sum / length) as u8));
            }
            if let Some(uuid) = request.query().get("uuid") {
                if let Ok(rating) = redis_conn.hget::<_, _, u8>(mod_str, uuid) {
                    own_ratings.insert(mod_str.to_owned(), Rating::from(rating));
                }
            }
        }

        let result = RatingResults {
            average: average_ratings,
            own: match request.query().get("uuid") {
                Some(_) => Some(own_ratings),
                None => None,
            },
        };
        response.set(MediaType::Json);
        json::encode(&result).unwrap()
    });

    webserver.listen("127.0.0.1:7998")
}
<commit_msg>save modlist<commit_after>extern crate rustc_serialize;
#[macro_use]
extern crate nickel;
extern crate redis;
extern crate r2d2;
extern crate r2d2_redis;
extern crate plugin;
extern crate typemap;

extern crate core;

use std::env;
use std::collections::HashMap;
use r2d2::NopErrorHandler;
use nickel::{Nickel, HttpRouter, JsonBody, MediaType, QueryString};
use nickel::status::StatusCode;
use core::ops::Deref;
use redis::{Commands, Connection};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;

use redis_middleware::{RedisMiddleware, RedisRequestExtensions};
mod redis_middleware;

#[derive(RustcDecodable, RustcEncodable)]
struct RatingSubmission {
    uuid: String,
    mod_str: String,
    rating: Rating,
}

#[derive(Clone, Copy, Debug)]
enum Rating {
    Poor = 0,
    BelowAverage,
    Average,
    AboveAverage,
    Excellent,
}

#[derive(RustcEncodable)]
struct RatingResults {
    average: HashMap<String, Rating>,
    own: Option<HashMap<String, Rating>>,
}

impl From<u8> for Rating {
    fn from(rating: u8) -> Self {
        match rating {
            0 => Rating::Poor,
            1 => Rating::BelowAverage,
            2 => Rating::Average,
            3 => Rating::AboveAverage,
            _ => Rating::Excellent,
        }
    }
}

impl Decodable for Rating {
    fn decode<D: Decoder>(d: &mut D) -> Result<Rating, D::Error> {
        let r = try!(d.read_u8());
        Ok(Rating::from(r))
    }
}

impl Encodable for Rating {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let as_u8 = *self as u8;
        s.emit_u8(as_u8)
    }
}

fn incr_requests(conn: &Connection) {
    if let Err(_) = conn.incr::<_, _, u64>("requests", 1) {
        println!("failed to incr request counter.")
    }
}

const OK_RESP: (StatusCode, &'static str) = (StatusCode::Ok, "ok");

fn main() {
    let mut webserver = Nickel::new();

    let redis_url = env::var("DATABASE_URL").unwrap_or("redis://localhost/3".to_owned());
    println!("connecting to redis @ {}", redis_url);

    let redispool = RedisMiddleware::new(&*redis_url, 3, Box::new(NopErrorHandler)).unwrap();
    webserver.utilize(redispool);

    webserver.post("/submit",
                   middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let sbm = try_with!(response, {
            request.json_as::<RatingSubmission>().map_err(|e| (StatusCode::BadRequest, e))
        });
        println!("{} rates {} as {:?}", sbm.uuid, sbm.mod_str, sbm.rating);
        let _: bool = try_with!(response, {
            redis_conn.hset("mods", &*sbm.mod_str, true).map_err(|e| (StatusCode::BadRequest, e))
        });
        let _: u8 = try_with!(response, {
            redis_conn.hset(sbm.mod_str, sbm.uuid, sbm.rating as u8).map_err(|e|
                (StatusCode::BadRequest, e)
            )
        });
        OK_RESP
    });

    webserver.get("/rating/:mod",
                  middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let mod_str = request.param("mod").unwrap();
        let ratings = try_with!(response, {
            redis_conn.hvals::<_, Vec<u8>>(mod_str).map_err(|e| (StatusCode::BadRequest, e))
        });
        let length = ratings.len();
        let mut sum = 0usize;
        for rating in ratings {
            sum += rating as usize;
        }
        match length {
            0 => (StatusCode::NotFound, "{\"not_found\": true}".to_owned()),
            _ => (StatusCode::Ok, format!("{}", sum / length)),
        }
    });

    webserver.get("/ratings",
                  middleware! { |request, mut response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);

        let mods = try_with!(response, {
            redis_conn.hkeys::<_, Vec<String>>("mods").map_err(|e| (StatusCode::BadRequest, e))
        });

        let mut own_ratings = HashMap::new();
        let mut average_ratings = HashMap::new();

        for mod_str in mods {
            let mod_str = mod_str.as_str();
            let ratings = try_with!(response, {
                redis_conn.hvals::<_, Vec<u8>>(mod_str).map_err(|e| (StatusCode::BadRequest, e))
            });
            let length = ratings.len();
            let mut sum = 0usize;
            for rating in ratings {
                sum += rating as usize;
            }
            if length > 0 {
                average_ratings.insert(mod_str.to_owned(), Rating::from((sum / length) as u8));
            }
            if let Some(uuid) = request.query().get("uuid") {
                if let Ok(rating) = redis_conn.hget::<_, _, u8>(mod_str, uuid) {
                    own_ratings.insert(mod_str.to_owned(), Rating::from(rating));
                }
            }
        }

        let result = RatingResults {
            average: average_ratings,
            own: match request.query().get("uuid") {
                Some(_) => Some(own_ratings),
                None => None,
            },
        };
        response.set(MediaType::Json);
        json::encode(&result).unwrap()
    });

    webserver.listen("127.0.0.1:7998")
}
<|endoftext|>


<commit_before>extern crate ncurses;

use super::chip_8::io;

#[derive(Default)]
pub struct Audio{}

impl io::Audio for Audio {
    fn beep(&self){
        ncurses::beep();
    }
}

enum Key {
    Key(u8),
    Und(i32),
}

pub struct Input<'a> {
    screen:&'a ncurses::SCREEN,
}

impl<'a> Input<'a> {
    fn map_key(key:i32) -> Key {
        match key {
            0x31 => Key::Key(0x0), // 1
            0x32 => Key::Key(0x1), // 2
            0x33 => Key::Key(0x2), // 3
            0x34 => Key::Key(0x3), // 4
            0x71 => Key::Key(0x4), // q
            0x77 => Key::Key(0x5), // w
            0x65 => Key::Key(0x6), // e
            0x72 => Key::Key(0x7), // r
            0x61 => Key::Key(0x8), // a
            0x73 => Key::Key(0x9), // s
            0x64 => Key::Key(0xA), // d
            0x66 => Key::Key(0xB), // f
            0x7A => Key::Key(0xC), // z
            0x78 => Key::Key(0xD), // x
            0x63 => Key::Key(0xE), // c
            0x76 => Key::Key(0xF), // v
            key => Key::Und(key),
        }
    }

    pub fn new(screen:&'a ncurses::SCREEN) -> Input<'a>{
        Input{screen:screen}
    }
}

impl<'a> io::Input for Input<'a> {
    fn get_keys(&self) -> Vec<u8> {
        let mut keys = Vec::<u8>::new();
        ncurses::nodelay(*self.screen, true);
        loop {
            match Input::map_key(ncurses::wgetch(*self.screen)) {
                Key::Key(key) => keys.push(key),
                Key::Und(ncurses::ERR) => break,
                _ =>{},
            }
        }
        ncurses::nodelay(*self.screen, false);
        keys
    }

    fn get_key(&self) -> u8 {
        loop {
            if let Key::Key(x) = Input::map_key(ncurses::wgetch(*self.screen)){
                return x;
            }
        }
    }
}

pub struct Display<'a> {
    screen:&'a ncurses::SCREEN,
}

impl<'a> Display<'a> {
    pub fn new(screen:&'a ncurses::SCREEN) -> Display<'a>{
        Display{screen:screen}
    }
}

impl<'a> io::Display for Display<'a> {
    fn set(&mut self, row:usize, col:usize, state:io::Pixel)
            -> Result<(),()> {
        let pixel:ncurses::chtype = match state {
            io::Pixel::On => 0x34,
            io::Pixel::Off => 0x20,
        };
        match ncurses::mvwaddch(*self.screen, row as i32, col as i32, pixel){
            ncurses::ERR => Err(()),
            _ => Ok(()),
        }
    }

    fn refresh(&mut self){
        ncurses::wrefresh(*self.screen);
    }
}
<commit_msg>made display white on black blocks<commit_after>extern crate ncurses;

use super::chip_8::io;

#[derive(Default)]
pub struct Audio{}

impl io::Audio for Audio {
    fn beep(&self){
        ncurses::beep();
    }
}

enum Key {
    Key(u8),
    Und(i32),
}

pub struct Input<'a> {
    screen:&'a ncurses::SCREEN,
}

impl<'a> Input<'a> {
    fn map_key(key:i32) -> Key {
        match key {
            0x31 => Key::Key(0x0), // 1
            0x32 => Key::Key(0x1), // 2
            0x33 => Key::Key(0x2), // 3
            0x34 => Key::Key(0x3), // 4
            0x71 => Key::Key(0x4), // q
            0x77 => Key::Key(0x5), // w
            0x65 => Key::Key(0x6), // e
            0x72 => Key::Key(0x7), // r
            0x61 => Key::Key(0x8), // a
            0x73 => Key::Key(0x9), // s
            0x64 => Key::Key(0xA), // d
            0x66 => Key::Key(0xB), // f
            0x7A => Key::Key(0xC), // z
            0x78 => Key::Key(0xD), // x
            0x63 => Key::Key(0xE), // c
            0x76 => Key::Key(0xF), // v
            key => Key::Und(key),
        }
    }

    pub fn new(screen:&'a ncurses::SCREEN) -> Input<'a>{
        Input{screen:screen}
    }
}

impl<'a> io::Input for Input<'a> {
    fn get_keys(&self) -> Vec<u8> {
        let mut keys = Vec::<u8>::new();
        ncurses::nodelay(*self.screen, true);
        loop {
            match Input::map_key(ncurses::wgetch(*self.screen)) {
                Key::Key(key) => keys.push(key),
                Key::Und(ncurses::ERR) => break,
                _ =>{},
            }
        }
        ncurses::nodelay(*self.screen, false);
        keys
    }

    fn get_key(&self) -> u8 {
        loop {
            if let Key::Key(x) = Input::map_key(ncurses::wgetch(*self.screen)){
                return x;
            }
        }
    }
}

pub struct Display<'a> {
    screen:&'a ncurses::SCREEN,
}

impl<'a> Display<'a> {
    pub fn new(screen:&'a ncurses::SCREEN) -> Display<'a>{
        Display{screen:screen}
    }
}

impl<'a> io::Display for Display<'a> {
    fn set(&mut self, row:usize, col:usize, state:io::Pixel) -> Result<(),()> {

        let attr = match state {
            io::Pixel::On => ncurses::A_NORMAL(),
            io::Pixel::Off => ncurses::A_STANDOUT(),
        };

        match ncurses::mvwchgat(
                *self.screen,
                row as i32,
                col as i32,
                1, attr, 0) {
            ncurses::ERR => Err(()),
            _ => Ok(()),
        }
    }

    fn refresh(&mut self){
        ncurses::wrefresh(*self.screen);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "nproc"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::os;

static NAME : &'static str = "nproc";
static VERSION : &'static str = "0.0.0";

pub fn uumain(args: Vec<String>) -> int {
    let opts = [
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(err) => fail!("{}", err),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] NAME...", NAME);
        println!("");
        print!("{}", getopts::usage("Print the number of cores available.", opts.as_slice()).as_slice());
        if matches.free.is_empty() {
            return 1;
        }
        return 0;
    }

    println!("{}", os::num_cpus());

    return 0
}
<commit_msg>nproc: support --all and --ignore and respect OMP_NUM_THREADS<commit_after>#![crate_name = "nproc"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]

extern crate getopts;

use std::os;

static NAME : &'static str = "nproc";
static VERSION : &'static str = "0.0.0";

#[path = "../common/util.rs"]
mod util;

pub fn uumain(args: Vec<String>) -> int {
    let opts = [
        getopts::optflag("", "all", "print the number of cores available to the system"),
        getopts::optopt("", "ignore", "ignore up to N cores", "N"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(err) => {
            show_error!("{}", err);
            return 1;
        }
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] NAME...", NAME);
        println!("");
        print!("{}", getopts::usage("Print the number of cores available to the current process.", opts));
        return 0;
    }

    let mut ignore = match matches.opt_str("ignore") {
        Some(numstr) => match from_str(numstr.as_slice()) {
            Some(num) => num,
            None => {
                show_error!("\"{}\" is not a valid number", numstr);
                return 1;
            }
        },
        None => 0
    };

    if !matches.opt_present("all") {
        ignore += match os::getenv("OMP_NUM_THREADS") {
            Some(threadstr) => match from_str(threadstr.as_slice()) {
                Some(num) => num,
                None => 0
            },
            None => 0
        };
    }

    let mut cores = os::num_cpus();
    if cores <= ignore {
        cores = 1;
    } else {
        cores -= ignore;
    }
    println!("{}", cores);

    return 0
}
<|endoftext|>


<commit_before>/// Generate the `is_equal` method for a `struct`
macro_rules! patchable_struct_is_equal {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn is_equal(&self, other: &Self) -> Result<()> {
            $(
                self.$field.is_equal(&other.$field)?;
            )*
            Ok(())
        }
    };
}

/// Generate the `make_hash` method for a `struct`
macro_rules! patchable_struct_hash {
    ($( $field:ident )*) => {
        fn make_hash<H: std::hash::Hasher>(&self, state: &mut H) {
            // Include the type name in the hash (to avoid clash when structs
            // of different types have the same values for different fields)
            use std::hash::Hash;
            type_name::<Self>().hash(state);
            // Include the hash of supplied fields. Because we include the type
            // name in the hash, we do no need to include the field names.
            $(
                self.$field.make_hash(state);
            )*
        }
    };
}

/// Generate the `diff` method for a `struct`
macro_rules! patchable_struct_diff {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn diff(&self, other: &Self, differ: &mut Differ) {
            $(
                differ.field(stringify!($field), &self.$field, &other.$field);
            )*
        }
    };
}

/// Generate the `apply_add` method for a `struct`
macro_rules! patchable_struct_apply_add {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn apply_add(&mut self, address: &mut Address, value: &Value) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_add(address, value),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_remove` method for a `struct`
macro_rules! patchable_struct_apply_remove {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn apply_remove(&mut self, address: &mut Address, items: usize) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_remove(address, items),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_replace` method for a `struct`
macro_rules! patchable_struct_apply_replace {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn apply_replace(&mut self, address: &mut Address, items: usize, value: &Value) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_replace(address, items, value),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_move` method for a `struct`
macro_rules! patchable_struct_apply_move {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn apply_move(&mut self, from: &mut Address, items: usize, to: &mut Address) -> Result<()> {
            if let (Some(Slot::Name(name)), Some(Slot::Name(_name_again))) = (from.pop_front(), to.pop_front()) {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_move(from, items, to),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_transform` method for a `struct`
macro_rules! patchable_struct_apply_transform {
    ($( $field:ident )*) => {
        #[allow(unused_variables)]
        fn apply_transform(&mut self, address: &mut Address, from: &str, to: &str) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_transform(address, from, to),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate a `impl Patchable` for a `struct`, passing
/// a list of fields for comparison, diffing, and applying ops.
macro_rules! patchable_struct {
    ($type:ty $(, $field:ident )*) => {
        impl Patchable for $type {
            patchable_struct_is_equal!($( $field )*);
            patchable_struct_hash!($( $field )*);
            patchable_struct_diff!($( $field )*);
            patchable_struct_apply_add!($( $field )*);
            patchable_struct_apply_remove!($( $field )*);
            patchable_struct_apply_replace!($( $field )*);
            patchable_struct_apply_move!($( $field )*);
            patchable_struct_apply_transform!($( $field )*);
        }
    };
}

/// Generate a `impl Patchable` for a `struct` that should
/// be replaced as a whole, rather than patching its fields separately.
///
/// Use this, for example, for `struct`s whose HTML encoding is more complicated
/// than a set of elements for each field.
///
/// The `diff` method returns a `Replace` operation and it only implements
/// `apply_replace`.
macro_rules! replaceable_struct {
    ($type:ty $(, $field:ident )*) => {
        impl Patchable for $type {
            patchable_struct_is_equal!($( $field )*);
            patchable_struct_hash!($( $field )*);

            fn diff(&self, other: &Self, differ: &mut Differ) {
                if !self.is_equal(other).is_ok() {
                    differ.replace(other)
                }
            }

            patchable_struct_apply_replace!($( $field )*);
        }
    };
}
<commit_msg>refactor(Node patches): Allow for optional trailing commas in macros<commit_after>/// Generate the `is_equal` method for a `struct`
macro_rules! patchable_struct_is_equal {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn is_equal(&self, other: &Self) -> Result<()> {
            $(
                self.$field.is_equal(&other.$field)?;
            )*
            Ok(())
        }
    };
}

/// Generate the `make_hash` method for a `struct`
macro_rules! patchable_struct_hash {
    ($($field:ident),* $(,)?) => {
        fn make_hash<H: std::hash::Hasher>(&self, state: &mut H) {
            // Include the type name in the hash (to avoid clash when structs
            // of different types have the same values for different fields)
            use std::hash::Hash;
            type_name::<Self>().hash(state);
            // Include the hash of supplied fields. Because we include the type
            // name in the hash, we do no need to include the field names.
            $(
                self.$field.make_hash(state);
            )*
        }
    };
}

/// Generate the `diff` method for a `struct`
macro_rules! patchable_struct_diff {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn diff(&self, other: &Self, differ: &mut Differ) {
            $(
                differ.field(stringify!($field), &self.$field, &other.$field);
            )*
        }
    };
}

/// Generate the `apply_add` method for a `struct`
macro_rules! patchable_struct_apply_add {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn apply_add(&mut self, address: &mut Address, value: &Value) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_add(address, value),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_remove` method for a `struct`
macro_rules! patchable_struct_apply_remove {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn apply_remove(&mut self, address: &mut Address, items: usize) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_remove(address, items),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_replace` method for a `struct`
macro_rules! patchable_struct_apply_replace {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn apply_replace(&mut self, address: &mut Address, items: usize, value: &Value) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_replace(address, items, value),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_move` method for a `struct`
macro_rules! patchable_struct_apply_move {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn apply_move(&mut self, from: &mut Address, items: usize, to: &mut Address) -> Result<()> {
            if let (Some(Slot::Name(name)), Some(Slot::Name(_name_again))) = (from.pop_front(), to.pop_front()) {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_move(from, items, to),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate the `apply_transform` method for a `struct`
macro_rules! patchable_struct_apply_transform {
    ($($field:ident),* $(,)?) => {
        #[allow(unused_variables)]
        fn apply_transform(&mut self, address: &mut Address, from: &str, to: &str) -> Result<()> {
            if let Some(Slot::Name(name)) = address.pop_front() {
                match name.as_str() {
                    $(
                        stringify!($field) => self.$field.apply_transform(address, from, to),
                    )*
                    _ => bail!(invalid_slot_name::<Self>(&name)),
                }
            } else {
                bail!(invalid_address::<Self>("first slot should be a name"))
            }
        }
    };
}

/// Generate a `impl Patchable` for a `struct`, passing
/// a list of fields for comparison, diffing, and applying ops.
macro_rules! patchable_struct {
    ($type:ty $(,$field:ident)* $(,)?) => {
        impl Patchable for $type {
            patchable_struct_is_equal!($($field,)*);
            patchable_struct_hash!($($field,)*);
            patchable_struct_diff!($($field,)*);
            patchable_struct_apply_add!($($field,)*);
            patchable_struct_apply_remove!($($field,)*);
            patchable_struct_apply_replace!($($field,)*);
            patchable_struct_apply_move!($($field,)*);
            patchable_struct_apply_transform!($($field,)*);
        }
    };
}

/// Generate a `impl Patchable` for a `struct` that should
/// be replaced as a whole, rather than patching its fields separately.
///
/// Use this, for example, for `struct`s whose HTML encoding is more complicated
/// than a set of elements for each field.
///
/// The `diff` method returns a `Replace` operation and it only implements
/// `apply_replace`.
macro_rules! replaceable_struct {
    ($type:ty $(,$field:ident)* $(,)?) => {
        impl Patchable for $type {
            patchable_struct_is_equal!($($field,)*);
            patchable_struct_hash!($($field,)*);

            fn diff(&self, other: &Self, differ: &mut Differ) {
                if !self.is_equal(other).is_ok() {
                    differ.replace(other)
                }
            }

            patchable_struct_apply_replace!($($field,)*);
        }
    };
}
<|endoftext|>


<commit_before>//! Error types for conversion to integral types.

use crate::convert::Infallible;
use crate::fmt;

/// The error type returned when a checked integral type conversion fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(pub(crate) ());

impl TryFromIntError {
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        "out of range integral type conversion attempted"
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl fmt::Display for TryFromIntError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(fmt)
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl From<Infallible> for TryFromIntError {
    fn from(x: Infallible) -> TryFromIntError {
        match x {}
    }
}

#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
    fn from(never: !) -> TryFromIntError {
        // Match rather than coerce to make sure that code like
        // `From<Infallible> for TryFromIntError` above will keep working
        // when `Infallible` becomes an alias to `!`.
        match never {}
    }
}

/// An error which can be returned when parsing an integer.
///
/// This error is used as the error type for the `from_str_radix()` functions
/// on the primitive integer types, such as [`i8::from_str_radix`].
///
/// # Potential causes
///
/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
/// in the string e.g., when it is obtained from the standard input.
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
///
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
///
/// # Example
///
/// ```
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {}", e);
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseIntError {
    pub(super) kind: IntErrorKind,
}

/// Enum to store the various types of errors that can cause parsing an integer to fail.
///
/// # Example
///
/// ```
/// # fn main() {
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {:?}", e.kind());
/// }
/// # }
/// ```
#[stable(feature = "int_error_matching", since = "1.47.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IntErrorKind {
    /// Value being parsed is empty.
    ///
    /// Among other causes, this variant will be constructed when parsing an empty string.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Empty,
    /// Contains an invalid digit in its context.
    ///
    /// Among other causes, this variant will be constructed when parsing a string that
    /// contains a non-asci char.
    ///
    /// This variant is also constructed when a `+` or `-` is misplaced within a string
    /// either on its own or in the middle of a number.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
    /// Integer is too large to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    PosOverflow,
    /// Integer is too small to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    NegOverflow,
    /// Value was Zero
    ///
    /// This variant will be emitted when the parsing string has a value of zero, which
    /// would be illegal for non-zero types.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Zero,
}

impl ParseIntError {
    /// Outputs the detailed cause of parsing an integer failing.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    pub fn kind(&self) -> &IntErrorKind {
        &self.kind
    }
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        match self.kind {
            IntErrorKind::Empty => "cannot parse integer from empty string",
            IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
            IntErrorKind::PosOverflow => "number too large to fit in target type",
            IntErrorKind::NegOverflow => "number too small to fit in target type",
            IntErrorKind::Zero => "number would be zero for non-zero type",
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for ParseIntError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(f)
    }
}
<commit_msg>asci -> ASCII<commit_after>//! Error types for conversion to integral types.

use crate::convert::Infallible;
use crate::fmt;

/// The error type returned when a checked integral type conversion fails.
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(pub(crate) ());

impl TryFromIntError {
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        "out of range integral type conversion attempted"
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl fmt::Display for TryFromIntError {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(fmt)
    }
}

#[stable(feature = "try_from", since = "1.34.0")]
impl From<Infallible> for TryFromIntError {
    fn from(x: Infallible) -> TryFromIntError {
        match x {}
    }
}

#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
    fn from(never: !) -> TryFromIntError {
        // Match rather than coerce to make sure that code like
        // `From<Infallible> for TryFromIntError` above will keep working
        // when `Infallible` becomes an alias to `!`.
        match never {}
    }
}

/// An error which can be returned when parsing an integer.
///
/// This error is used as the error type for the `from_str_radix()` functions
/// on the primitive integer types, such as [`i8::from_str_radix`].
///
/// # Potential causes
///
/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace
/// in the string e.g., when it is obtained from the standard input.
/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing.
///
/// [`str.trim()`]: ../../std/primitive.str.html#method.trim
/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix
///
/// # Example
///
/// ```
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {}", e);
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseIntError {
    pub(super) kind: IntErrorKind,
}

/// Enum to store the various types of errors that can cause parsing an integer to fail.
///
/// # Example
///
/// ```
/// # fn main() {
/// if let Err(e) = i32::from_str_radix("a12", 10) {
///     println!("Failed conversion to i32: {:?}", e.kind());
/// }
/// # }
/// ```
#[stable(feature = "int_error_matching", since = "1.47.0")]
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IntErrorKind {
    /// Value being parsed is empty.
    ///
    /// Among other causes, this variant will be constructed when parsing an empty string.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Empty,
    /// Contains an invalid digit in its context.
    ///
    /// Among other causes, this variant will be constructed when parsing a string that
    /// contains a non-ASCII char.
    ///
    /// This variant is also constructed when a `+` or `-` is misplaced within a string
    /// either on its own or in the middle of a number.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    InvalidDigit(#[stable(feature = "int_error_matching", since = "1.47.0")] char),
    /// Integer is too large to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    PosOverflow,
    /// Integer is too small to store in target integer type.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    NegOverflow,
    /// Value was Zero
    ///
    /// This variant will be emitted when the parsing string has a value of zero, which
    /// would be illegal for non-zero types.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    Zero,
}

impl ParseIntError {
    /// Outputs the detailed cause of parsing an integer failing.
    #[stable(feature = "int_error_matching", since = "1.47.0")]
    pub fn kind(&self) -> &IntErrorKind {
        &self.kind
    }
    #[unstable(
        feature = "int_error_internals",
        reason = "available through Error trait and this method should \
                  not be exposed publicly",
        issue = "none"
    )]
    #[doc(hidden)]
    pub fn __description(&self) -> &str {
        match self.kind {
            IntErrorKind::Empty => "cannot parse integer from empty string",
            IntErrorKind::InvalidDigit(_) => "invalid digit found in string",
            IntErrorKind::PosOverflow => "number too large to fit in target type",
            IntErrorKind::NegOverflow => "number too small to fit in target type",
            IntErrorKind::Zero => "number would be zero for non-zero type",
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for ParseIntError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.__description().fmt(f)
    }
}
<|endoftext|>


<commit_before>use internal::prelude::*;
use internal::ws_impl::ReceiverExt;
use model::event::{Event, GatewayEvent};
use parking_lot::Mutex as ParkingLotMutex;
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use super::super::super::{EventHandler, dispatch};
use super::{LockedShard, ShardId, ShardManagerMessage};
use typemap::ShareMap;
use websocket::WebSocketError;

#[cfg(feature = "framework")]
use framework::Framework;
#[cfg(feature = "framework")]
use std::sync::Mutex;

pub struct ShardRunner<H: EventHandler + 'static> {
    data: Arc<ParkingLotMutex<ShareMap>>,
    event_handler: Arc<H>,
    #[cfg(feature = "framework")]
    framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
    manager_tx: Sender<ShardManagerMessage>,
    runner_rx: Receiver<ShardManagerMessage>,
    runner_tx: Sender<ShardManagerMessage>,
    shard: LockedShard,
    shard_info: [u64; 2],
}

impl<H: EventHandler + 'static> ShardRunner<H> {
    #[cfg(feature = "framework")]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            framework,
            manager_tx,
            shard,
            shard_info,
        }
    }

    #[cfg(not(feature = "framework"))]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            manager_tx,
            shard,
            shard_info,
        }
    }

    pub fn run(&mut self) -> Result<()> {
        debug!("[ShardRunner {:?}] Running", self.shard_info);

        loop {
            {
                let mut shard = self.shard.lock();
                let incoming = self.runner_rx.try_recv();

                // Check for an incoming message over the runner channel.
                //
                // If the message is to shutdown, first verify the ID so we know
                // for certain this runner is to shutdown.
                if let Ok(ShardManagerMessage::Shutdown(id)) = incoming {
                    if id.0 == self.shard_info[0] {
                        let _ = shard.shutdown_clean();

                        return Ok(());
                    }
                }

                if let Err(why) = shard.check_heartbeat() {
                    error!("Failed to heartbeat and reconnect: {:?}", why);

                    return self.request_restart();
                }

                #[cfg(feature = "voice")]
                {
                    shard.cycle_voice_recv();
                }
            }

            let (event, successful) = self.recv_events();

            if let Some(event) = event {
                dispatch(
                    event,
                    &self.shard,
                    #[cfg(feature = "framework")]
                    &self.framework,
                    &self.data,
                    &self.event_handler,
                );
            }

            if !successful && !self.shard.lock().stage().is_connecting() {
                return self.request_restart();
            }
        }
    }

    pub(super) fn runner_tx(&self) -> Sender<ShardManagerMessage> {
        self.runner_tx.clone()
    }

    /// Returns a received event, as well as whether reading the potentially
    /// present event was successful.
    fn recv_events(&mut self) -> (Option<Event>, bool) {
        let mut shard = self.shard.lock();

        let gw_event = match shard.client.recv_json(GatewayEvent::decode) {
            Err(Error::WebSocket(WebSocketError::IoError(_))) => {
                // Check that an amount of time at least double the
                // heartbeat_interval has passed.
                //
                // If not, continue on trying to receive messages.
                //
                // If it has, attempt to auto-reconnect.
                let last = shard.last_heartbeat_ack();
                let interval = shard.heartbeat_interval();

                if let (Some(last_heartbeat_ack), Some(interval)) = (last, interval) {
                    let seconds_passed = last_heartbeat_ack.elapsed().as_secs();
                    let interval_in_secs = interval / 1000;

                    if seconds_passed <= interval_in_secs * 2 {
                        return (None, true);
                    }
                } else {
                    return (None, true);
                }

                debug!("Attempting to auto-reconnect");

                if let Err(why) = shard.autoreconnect() {
                    error!("Failed to auto-reconnect: {:?}", why);
                }

                return (None, true);
            },
            Err(Error::WebSocket(WebSocketError::NoDataAvailable)) => {
                // This is hit when the websocket client dies this will be
                // hit every iteration.
                return (None, false);
            },
            other => other,
        };

        let event = match gw_event {
            Ok(Some(event)) => Ok(event),
            Ok(None) => return (None, true),
            Err(why) => Err(why),
        };

        let event = match shard.handle_event(event) {
            Ok(Some(event)) => event,
            Ok(None) => return (None, true),
            Err(why) => {
                error!("Shard handler received err: {:?}", why);

                return (None, true);
            },
         };

        (Some(event), true)
    }

    fn request_restart(&self) -> Result<()> {
        debug!("[ShardRunner {:?}] Requesting restart", self.shard_info);
        let msg = ShardManagerMessage::Restart(ShardId(self.shard_info[0]));
        let _ = self.manager_tx.send(msg);

        Ok(())
    }
}
<commit_msg>Rename an internal Shard Runner method<commit_after>use internal::prelude::*;
use internal::ws_impl::ReceiverExt;
use model::event::{Event, GatewayEvent};
use parking_lot::Mutex as ParkingLotMutex;
use std::sync::mpsc::{self, Receiver, Sender};
use std::sync::Arc;
use super::super::super::{EventHandler, dispatch};
use super::{LockedShard, ShardId, ShardManagerMessage};
use typemap::ShareMap;
use websocket::WebSocketError;

#[cfg(feature = "framework")]
use framework::Framework;
#[cfg(feature = "framework")]
use std::sync::Mutex;

pub struct ShardRunner<H: EventHandler + 'static> {
    data: Arc<ParkingLotMutex<ShareMap>>,
    event_handler: Arc<H>,
    #[cfg(feature = "framework")]
    framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
    manager_tx: Sender<ShardManagerMessage>,
    runner_rx: Receiver<ShardManagerMessage>,
    runner_tx: Sender<ShardManagerMessage>,
    shard: LockedShard,
    shard_info: [u64; 2],
}

impl<H: EventHandler + 'static> ShardRunner<H> {
    #[cfg(feature = "framework")]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               framework: Arc<Mutex<Option<Box<Framework + Send>>>>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            framework,
            manager_tx,
            shard,
            shard_info,
        }
    }

    #[cfg(not(feature = "framework"))]
    pub fn new(shard: LockedShard,
               manager_tx: Sender<ShardManagerMessage>,
               data: Arc<ParkingLotMutex<ShareMap>>,
               event_handler: Arc<H>) -> Self {
        let (tx, rx) = mpsc::channel();
        let shard_info = shard.lock().shard_info();

        Self {
            runner_rx: rx,
            runner_tx: tx,
            data,
            event_handler,
            manager_tx,
            shard,
            shard_info,
        }
    }

    pub fn run(&mut self) -> Result<()> {
        debug!("[ShardRunner {:?}] Running", self.shard_info);

        loop {
            {
                let mut shard = self.shard.lock();
                let incoming = self.runner_rx.try_recv();

                // Check for an incoming message over the runner channel.
                //
                // If the message is to shutdown, first verify the ID so we know
                // for certain this runner is to shutdown.
                if let Ok(ShardManagerMessage::Shutdown(id)) = incoming {
                    if id.0 == self.shard_info[0] {
                        let _ = shard.shutdown_clean();

                        return Ok(());
                    }
                }

                if let Err(why) = shard.check_heartbeat() {
                    error!("Failed to heartbeat and reconnect: {:?}", why);

                    return self.request_restart();
                }

                #[cfg(feature = "voice")]
                {
                    shard.cycle_voice_recv();
                }
            }

            let (event, successful) = self.recv_event();

            if let Some(event) = event {
                dispatch(
                    event,
                    &self.shard,
                    #[cfg(feature = "framework")]
                    &self.framework,
                    &self.data,
                    &self.event_handler,
                );
            }

            if !successful && !self.shard.lock().stage().is_connecting() {
                return self.request_restart();
            }
        }
    }

    pub(super) fn runner_tx(&self) -> Sender<ShardManagerMessage> {
        self.runner_tx.clone()
    }

    /// Returns a received event, as well as whether reading the potentially
    /// present event was successful.
    fn recv_event(&mut self) -> (Option<Event>, bool) {
        let mut shard = self.shard.lock();

        let gw_event = match shard.client.recv_json(GatewayEvent::decode) {
            Err(Error::WebSocket(WebSocketError::IoError(_))) => {
                // Check that an amount of time at least double the
                // heartbeat_interval has passed.
                //
                // If not, continue on trying to receive messages.
                //
                // If it has, attempt to auto-reconnect.
                let last = shard.last_heartbeat_ack();
                let interval = shard.heartbeat_interval();

                if let (Some(last_heartbeat_ack), Some(interval)) = (last, interval) {
                    let seconds_passed = last_heartbeat_ack.elapsed().as_secs();
                    let interval_in_secs = interval / 1000;

                    if seconds_passed <= interval_in_secs * 2 {
                        return (None, true);
                    }
                } else {
                    return (None, true);
                }

                debug!("Attempting to auto-reconnect");

                if let Err(why) = shard.autoreconnect() {
                    error!("Failed to auto-reconnect: {:?}", why);
                }

                return (None, true);
            },
            Err(Error::WebSocket(WebSocketError::NoDataAvailable)) => {
                // This is hit when the websocket client dies this will be
                // hit every iteration.
                return (None, false);
            },
            other => other,
        };

        let event = match gw_event {
            Ok(Some(event)) => Ok(event),
            Ok(None) => return (None, true),
            Err(why) => Err(why),
        };

        let event = match shard.handle_event(event) {
            Ok(Some(event)) => event,
            Ok(None) => return (None, true),
            Err(why) => {
                error!("Shard handler received err: {:?}", why);

                return (None, true);
            },
         };

        (Some(event), true)
    }

    fn request_restart(&self) -> Result<()> {
        debug!("[ShardRunner {:?}] Requesting restart", self.shard_info);
        let msg = ShardManagerMessage::Restart(ShardId(self.shard_info[0]));
        let _ = self.manager_tx.send(msg);

        Ok(())
    }
}
<|endoftext|>