<commit_before>use std::ffi::CStr;
use std::fmt;
use std::str;
use libc::{c_char, c_void};
use malloc_buf::MallocBuffer;

use runtime::{Class, Object, Sel};

#[cfg(target_pointer_width = "64")]
const CODE_INLINE_CAP: usize = 30;

#[cfg(target_pointer_width = "32")]
const CODE_INLINE_CAP: usize = 14;

enum Code {
    Slice(&'static str),
    Owned(String),
    Inline(u8, [u8; CODE_INLINE_CAP]),
    Malloc(MallocBuffer<u8>)
}

/// An Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub struct Encoding {
    code: Code,
}

impl Encoding {
    /// Constructs an `Encoding` from its string representation.
    /// Unsafe because the caller must ensure the string is a valid encoding.
    pub unsafe fn from_str(code: &str) -> Encoding {
        from_str(code)
    }

    /// Returns self as a `str`.
    pub fn as_str(&self) -> &str {
        match self.code {
            Code::Slice(code) => code,
            Code::Owned(ref code) => code,
            Code::Inline(len, ref bytes) => unsafe {
                str::from_utf8_unchecked(&bytes[..len as usize])
            },
            Code::Malloc(ref buf) => unsafe {
                str::from_utf8_unchecked(&buf[..buf.len() - 1])
            },
        }
    }
}

impl Clone for Encoding {
    fn clone(&self) -> Encoding {
        if let Code::Slice(code) = self.code {
            from_static_str(code)
        } else {
            from_str(self.as_str())
        }
    }
}

impl PartialEq for Encoding {
    fn eq(&self, other: &Encoding) -> bool {
        self.as_str() == other.as_str()
    }
}

impl fmt::Debug for Encoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

pub fn from_static_str(code: &'static str) -> Encoding {
    Encoding { code: Code::Slice(code) }
}

pub fn from_str(code: &str) -> Encoding {
    if code.len() > CODE_INLINE_CAP {
        Encoding { code: Code::Owned(code.to_owned()) }
    } else {
        let mut bytes = [0; CODE_INLINE_CAP];
        for (dst, byte) in bytes.iter_mut().zip(code.bytes()) {
            *dst = byte;
        }
        Encoding { code: Code::Inline(code.len() as u8, bytes) }
    }
}

pub unsafe fn from_malloc_str(ptr: *mut c_char) -> Encoding {
    let s = CStr::from_ptr(ptr);
    let bytes = s.to_bytes_with_nul();
    assert!(str::from_utf8(bytes).is_ok());
    let buf = MallocBuffer::new(ptr as *mut u8, bytes.len()).unwrap();
    Encoding { code: Code::Malloc(buf) }
}

/// Types that have an Objective-C type encoding.
///
/// Unsafe because Objective-C will make assumptions about the type (like its
/// size and alignment) from its encoding, so the implementer must verify that
/// the encoding is accurate.
pub unsafe trait Encode {
    /// Returns the Objective-C type encoding for Self.
    fn encode() -> Encoding;
}

macro_rules! encode_impls {
    ($($t:ty : $s:expr,)*) => ($(
        unsafe impl Encode for $t {
            fn encode() -> Encoding { from_static_str($s) }
        }
    )*);
}

encode_impls!(
    i8: "c",
    i16: "s",
    i32: "i",
    i64: "q",
    u8: "C",
    u16: "S",
    u32: "I",
    u64: "Q",
    f32: "f",
    f64: "d",
    bool: "B",
    (): "v",
    *mut c_char: "*",
    *const c_char: "r*",
    *mut c_void: "^v",
    *const c_void: "r^v",
    Sel: ":",
);

unsafe impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { i32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { i64::encode() }
}

unsafe impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { u32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { u64::encode() }
}

macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }
    );
}

encode_message_impl!("@", Object);

encode_message_impl!("#", Class);

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::{Encode, Encoding};

    #[test]
    fn test_encode() {
        assert!(u32::encode().as_str() == "I");
        assert!(<()>::encode().as_str() == "v");
        assert!(<&Object>::encode().as_str() == "@");
        assert!(<*mut Object>::encode().as_str() == "@");
        assert!(<&Class>::encode().as_str() == "#");
        assert!(Sel::encode().as_str() == ":");
    }

    #[test]
    fn test_inline_encoding() {
        let enc = unsafe { Encoding::from_str("C") };
        assert!(enc.as_str() == "C");

        let enc2 = enc.clone();
        assert!(enc2 == enc);
        assert!(enc2.as_str() == "C");
    }

    #[test]
    fn test_owned_encoding() {
        let s = "{Test=CCCCCCCCCCCCCCCCCCCCCCCCC}";
        let enc = unsafe { Encoding::from_str(s) };
        assert!(enc.as_str() == s);

        let enc2 = enc.clone();
        assert!(enc2 == enc);
        assert!(enc2.as_str() == s);
    }
}
<commit_msg>Strip qualifiers when comparing Encodings.<commit_after>use std::ffi::CStr;
use std::fmt;
use std::str;
use libc::{c_char, c_void};
use malloc_buf::MallocBuffer;

use runtime::{Class, Object, Sel};

const QUALIFIERS: &'static [char] = &[
    'r', // const
    'n', // in
    'N', // inout
    'o', // out
    'O', // bycopy
    'R', // byref
    'V', // oneway
];

#[cfg(target_pointer_width = "64")]
const CODE_INLINE_CAP: usize = 30;

#[cfg(target_pointer_width = "32")]
const CODE_INLINE_CAP: usize = 14;

enum Code {
    Slice(&'static str),
    Owned(String),
    Inline(u8, [u8; CODE_INLINE_CAP]),
    Malloc(MallocBuffer<u8>)
}

/// An Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
pub struct Encoding {
    code: Code,
}

impl Encoding {
    /// Constructs an `Encoding` from its string representation.
    /// Unsafe because the caller must ensure the string is a valid encoding.
    pub unsafe fn from_str(code: &str) -> Encoding {
        from_str(code)
    }

    /// Returns self as a `str`.
    pub fn as_str(&self) -> &str {
        match self.code {
            Code::Slice(code) => code,
            Code::Owned(ref code) => code,
            Code::Inline(len, ref bytes) => unsafe {
                str::from_utf8_unchecked(&bytes[..len as usize])
            },
            Code::Malloc(ref buf) => unsafe {
                str::from_utf8_unchecked(&buf[..buf.len() - 1])
            },
        }
    }
}

impl Clone for Encoding {
    fn clone(&self) -> Encoding {
        if let Code::Slice(code) = self.code {
            from_static_str(code)
        } else {
            from_str(self.as_str())
        }
    }
}

impl PartialEq for Encoding {
    fn eq(&self, other: &Encoding) -> bool {
        // strip qualifiers when comparing
        let s = self.as_str().trim_left_matches(QUALIFIERS);
        let o = other.as_str().trim_left_matches(QUALIFIERS);
        s == o
    }
}

impl fmt::Debug for Encoding {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

pub fn from_static_str(code: &'static str) -> Encoding {
    Encoding { code: Code::Slice(code) }
}

pub fn from_str(code: &str) -> Encoding {
    if code.len() > CODE_INLINE_CAP {
        Encoding { code: Code::Owned(code.to_owned()) }
    } else {
        let mut bytes = [0; CODE_INLINE_CAP];
        for (dst, byte) in bytes.iter_mut().zip(code.bytes()) {
            *dst = byte;
        }
        Encoding { code: Code::Inline(code.len() as u8, bytes) }
    }
}

pub unsafe fn from_malloc_str(ptr: *mut c_char) -> Encoding {
    let s = CStr::from_ptr(ptr);
    let bytes = s.to_bytes_with_nul();
    assert!(str::from_utf8(bytes).is_ok());
    let buf = MallocBuffer::new(ptr as *mut u8, bytes.len()).unwrap();
    Encoding { code: Code::Malloc(buf) }
}

/// Types that have an Objective-C type encoding.
///
/// Unsafe because Objective-C will make assumptions about the type (like its
/// size and alignment) from its encoding, so the implementer must verify that
/// the encoding is accurate.
pub unsafe trait Encode {
    /// Returns the Objective-C type encoding for Self.
    fn encode() -> Encoding;
}

macro_rules! encode_impls {
    ($($t:ty : $s:expr,)*) => ($(
        unsafe impl Encode for $t {
            fn encode() -> Encoding { from_static_str($s) }
        }
    )*);
}

encode_impls!(
    i8: "c",
    i16: "s",
    i32: "i",
    i64: "q",
    u8: "C",
    u16: "S",
    u32: "I",
    u64: "Q",
    f32: "f",
    f64: "d",
    bool: "B",
    (): "v",
    *mut c_char: "*",
    *const c_char: "r*",
    *mut c_void: "^v",
    *const c_void: "r^v",
    Sel: ":",
);

unsafe impl Encode for isize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { i32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { i64::encode() }
}

unsafe impl Encode for usize {
    #[cfg(target_pointer_width = "32")]
    fn encode() -> Encoding { u32::encode() }

    #[cfg(target_pointer_width = "64")]
    fn encode() -> Encoding { u64::encode() }
}

macro_rules! encode_message_impl {
    ($code:expr, $name:ident) => (
        encode_message_impl!($code, $name,);
    );
    ($code:expr, $name:ident, $($t:ident),*) => (
        unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }

        unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
            fn encode() -> Encoding { from_static_str($code) }
        }
    );
}

encode_message_impl!("@", Object);

encode_message_impl!("#", Class);

#[cfg(test)]
mod tests {
    use runtime::{Class, Object, Sel};
    use super::{Encode, Encoding};

    #[test]
    fn test_encode() {
        assert!(u32::encode().as_str() == "I");
        assert!(<()>::encode().as_str() == "v");
        assert!(<&Object>::encode().as_str() == "@");
        assert!(<*mut Object>::encode().as_str() == "@");
        assert!(<&Class>::encode().as_str() == "#");
        assert!(Sel::encode().as_str() == ":");
    }

    #[test]
    fn test_inline_encoding() {
        let enc = unsafe { Encoding::from_str("C") };
        assert!(enc.as_str() == "C");

        let enc2 = enc.clone();
        assert!(enc2 == enc);
        assert!(enc2.as_str() == "C");
    }

    #[test]
    fn test_owned_encoding() {
        let s = "{Test=CCCCCCCCCCCCCCCCCCCCCCCCC}";
        let enc = unsafe { Encoding::from_str(s) };
        assert!(enc.as_str() == s);

        let enc2 = enc.clone();
        assert!(enc2 == enc);
        assert!(enc2.as_str() == s);
    }
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate png;

use std::collections::HashMap;
use std::default::Default;
use time;

use cgmath::{Matrix4, Point3, Vector3};

#[cfg(target_os = "android")]
use egl_context::EglContext;
use gl;
use gl::Texture;
use mesh;
use program::{Buffers, Program};
use world::{Chunk, Point2, World};
#[cfg(target_os = "linux")]
use x11::{PollEventsIterator, XWindow};

#[cfg(target_os = "android")]
pub struct EngineImpl {
  pub egl_context: Option<Box<EglContext>>,
  pub program: Option<Program>,
}

#[cfg(target_os = "android")]
impl Default for EngineImpl {
  fn default() -> EngineImpl {
    EngineImpl {
      egl_context: None,
      program: None,
    }
  }
}

#[cfg(target_os = "linux")]
pub struct EngineImpl {
  pub window: XWindow,
  pub program: Program,
}

/// Field of view.
pub struct Fov {
  angle: f32,  // in xz plane, in degrees from (0, 0, -1).
}

impl Fov {
  fn inc_angle(&mut self, degrees: f32) {
    self.angle += degrees;
    if self.angle > 360.0 {
      self.angle -= 360.0;
    }
  }
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  fov: Fov,
  /// GL projection matrix
  projection_matrix: Matrix4<f32>,
  /// Texture atlas.
  texture: Texture,
  world: World,
  buffers: HashMap<Chunk, Buffers>,
}

impl Engine {
  #[cfg(target_os = "android")]
  pub fn new() -> Engine {
    Engine {
      engine_impl: Default::default(),
      animating: false,
      fov: Fov {
        angle: 0.0,
      },
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: World::new(&Point2::new(0.0, 0.0), FAR_PLANE),
      buffers: HashMap::new(),
    }
  }

  #[cfg(target_os = "linux")]
  pub fn new(window: XWindow, program: Program) -> Engine {
    Engine {
      engine_impl: EngineImpl {
        window: window,
        program: program,
      },
      animating: false,
      fov: Fov {
        angle: 0.0,
      },
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: World::new(&Point2::new(0.0, 0.0), FAR_PLANE),
      buffers: HashMap::new(),
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "android")]
  pub fn init(&mut self, egl_context: Box<EglContext>, texture_atlas_bytes: &[u8]) {
    self.engine_impl.egl_context = Some(egl_context);

    self.engine_impl.program = match Program::new() {
      Ok(p) => Some(p),
      Err(e) => panic!("Program failed: {:?}", e),
    };

    self.common_init(texture_atlas_bytes);

    if let Some(ref p) = self.engine_impl.program {
      p.set_texture_unit(0);
    }

    // Silly gymnastics to satisfy the borrow checker.
    let wh = if let Some(ref ec) = self.engine_impl.egl_context {
      Some((ec.width, ec.height))
    } else {
      None
    };
    if let Some((w, h)) = wh {
      self.set_viewport(w, h);
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "linux")]
  pub fn init(&mut self, texture_atlas_bytes: &[u8]) {
    self.common_init(texture_atlas_bytes);
    self.engine_impl.program.set_texture_unit(0);
  }

  fn common_init(&mut self, texture_atlas_bytes: &[u8]) {
    // Set the background clear color to sky blue.
    gl::clear_color(0.5, 0.69, 1.0, 1.0);

    // Enable reverse face culling.
    gl::enable(gl::CULL_FACE);
    // Enable depth test.
    gl::enable(gl::DEPTH_TEST);
    gl::depth_func(gl::LEQUAL);

    // Set up textures.
    self.texture = Engine::load_texture_atlas(texture_atlas_bytes);
    gl::active_texture(gl::TEXTURE0);
    gl::bind_texture_2d(self.texture);

    self.load_meshes();
  }

  #[cfg(target_os = "android")]
  fn load_meshes(&mut self) {
    let start_s = time::precise_time_s();
    log!("*** Loading meshes...");

    if let Some(ref mut p) = self.engine_impl.program {
      for (c, bs) in self.world.chunk_blocks() {
        let vertices = mesh::create_mesh_vertices(bs, &self.world);
        let buffers = p.upload_vertices(&vertices);
        let c = (*c).clone();
        self.buffers.insert(c, buffers);
      }
    }

    let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
    log!("*** Loaded meshes: {:.3}ms, {} chunks", spent_ms, self.buffers.len());
  }

  #[cfg(target_os = "linux")]
  fn load_meshes(&mut self) {
    let start_s = time::precise_time_s();
    log!("*** Loading meshes...");

    let p = &self.engine_impl.program;
    for (c, bs) in self.world.chunk_blocks() {
      let vertices = mesh::create_mesh_vertices(bs, &self.world);
      let buffers = p.upload_vertices(&vertices);
      let c = (*c).clone();
      self.buffers.insert(c, buffers);
    }

    let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
    log!("*** Loaded meshes: {:.3}ms, {} chunks", spent_ms, self.buffers.len());
  }

  pub fn set_viewport(&mut self, w: i32, h: i32) {
    gl::viewport(0, 0, w, h);
    self.projection_matrix = projection_matrix(w, h);
  }

  /// Load texture atlas from assets folder.
  fn load_texture_atlas(texture_atlas_bytes: &[u8]) -> Texture {
    let image = png::load_png_from_memory(texture_atlas_bytes)
      .unwrap_or_else(|s| panic!("load_png_from_memory() failed: {}", s));

    let pixels = match image.pixels {
      png::PixelsByColorType::RGBA8(v) => v,
      _ => {
        let color_type = match image.pixels {
            png::PixelsByColorType::K8(_) => "K8",
            png::PixelsByColorType::KA8(_) => "KA8",
            png::PixelsByColorType::RGB8(_) => "RGB8",
            png::PixelsByColorType::RGBA8(_) => panic!("Should not happen"),
        };
        panic!("Only RGBA8 image format supported, was: {}", color_type);
      }
    };

    let texture = gl::gen_texture();
    gl::bind_texture_2d(texture);
    gl::texture_2d_param(gl::TEXTURE_MIN_FILTER, gl::NEAREST_MIPMAP_LINEAR);
    gl::texture_2d_param(gl::TEXTURE_MAG_FILTER, gl::NEAREST);
    gl::texture_2d_param(gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
    gl::texture_2d_param(gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
    gl::texture_2d_image_rgba(image.width as i32, image.height as i32, &pixels);
    gl::generate_mipmap_2d();
    gl::bind_texture_2d(0);

    texture
  }

  /// Draw a frame.
  #[cfg(target_os = "android")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    match self.engine_impl.egl_context {
      None => return,  // No display.
      Some(ref egl_context) => {
        gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

        match self.engine_impl.program {
          Some(ref p) => {
            if let Some(e) = self.world.eye() {
              // Compute the composite mvp_matrix and send it to program.  Model matrix
              // is always identity so instead of MVP = P * V * M just do MVP = P * V.
              let mvp_matrix = self.projection_matrix * view_matrix(&e, self.fov.angle);
              p.set_mvp_matrix(mvp_matrix);

              // Finally, draw the cube mesh.
              // TODO: Draw only meshes for only visible chunks within FOV.
              for bs in self.buffers.values() {
                p.bind_buffers(bs);
                gl::draw_elements_triangles_u16(bs.index_count);
                p.unbind_buffers();
              }
            }
          },
          None => panic!("Missing program, should never happen"),
        }

        egl_context.swap_buffers();
      }
    }
  }

  /// Draw a frame.
  #[cfg(target_os = "linux")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

    let p = &self.engine_impl.program;

    if let Some(e) = self.world.eye() {
      // Compute the composite mvp_matrix and send it to program.  Model matrix
      // is always identity so instead of MVP = P * V * M just do MVP = P * V.
      let mvp_matrix = self.projection_matrix * view_matrix(&e, self.fov.angle);
      p.set_mvp_matrix(mvp_matrix);

      // Finally, draw the cube meshes for all chunks.
      // TODO: Draw only meshes for only visible chunks within FOV.
      for bs in self.buffers.values() {
        p.bind_buffers(bs);
        gl::draw_elements_triangles_u16(bs.index_count);
        p.unbind_buffers();
      }
    }

    self.engine_impl.window.swap_buffers();
    self.engine_impl.window.flush();
  }

  /// Update for time passed and draw a frame.
  pub fn update_draw(&mut self) {
    if self.animating {
      // Done processing events; draw next animation frame.
      // Do a complete rotation every 10 seconds, assuming 60 FPS.
      self.fov.inc_angle(360.0 / 600.0);

      // Drawing is throttled to the screen update rate, so there is no need to do timing here.
      self.draw();
    }
  }

  /// Terminate the engine.
  #[cfg(target_os = "android")]
  pub fn term(&mut self) {
    self.animating = false;
    // Drop the program and the EGL context.
    self.engine_impl = Default::default();
    log!("*** Renderer terminated");
  }

  /// Called when window gains input focus.
  pub fn gained_focus(&mut self) {
    self.animating = true;
  }

  /// Called when window loses input focus.
  pub fn lost_focus(&mut self) {
    self.animating = false;
  }

  #[cfg(target_os = "linux")]
  pub fn is_closed(&self) -> bool {
    self.engine_impl.window.is_closed()
  }

  #[cfg(target_os = "linux")]
  pub fn poll_events(&self) -> PollEventsIterator {
    self.engine_impl.window.poll_events()
  }
}

/// A view matrix, eye is at (p.x, p.y + 2.12, p.z), rotating in horizontal plane clockwise
/// (thus the world is rotating counter-clockwise) and looking at
/// (p.x + sin α, p.y + 2.12, p.z - cos α).
fn view_matrix(p: &Point3<i32>, angle: f32) -> Matrix4<f32> {
  let y = p.y as f32 + 2.12;  // 0.5 for half block under feet + 1.62 up to eye height.
  let (s, c) = angle.to_radians().sin_cos();

  let eye = Point3::new(p.x as f32, y, p.z as f32);
  // Start with α == 0, looking at (p.x, y, p.z - 1).
  let center = Point3::new(p.x as f32 + s, y, p.z as f32 - c);
  let up = Vector3::new(0.0, 1.0, 0.0);
  Matrix4::look_at(&eye, &center, &up)
}

const NEAR_PLANE: f32 = 0.1;
const FAR_PLANE: f32 = 60.0;
const FIELD_OF_VIEW_DEGREES: f32 = 70.0;

/// Perspective projection matrix as frustum matrix.
fn projection_matrix(width: i32, height: i32) -> Matrix4<f32> {
  let inverse_aspect = height as f32 / width as f32;
  let field_of_view = FIELD_OF_VIEW_DEGREES.to_radians();

  let right = NEAR_PLANE * (field_of_view / 2.0).tan();
  let left = -right;
  let top = right * inverse_aspect;
  let bottom = -top;
  let near = NEAR_PLANE;
  let far = FAR_PLANE;
  cgmath::frustum(left, right, bottom, top, near, far)
}
<commit_msg>Rename Fov.angle into center_angle_degrees.  Move view_matrix into Fov.<commit_after>extern crate cgmath;
extern crate png;

use std::collections::HashMap;
use std::default::Default;
use time;

use cgmath::{Matrix4, Point3, Vector3};

#[cfg(target_os = "android")]
use egl_context::EglContext;
use gl;
use gl::Texture;
use mesh;
use program::{Buffers, Program};
use world::{Chunk, Point2, World};
#[cfg(target_os = "linux")]
use x11::{PollEventsIterator, XWindow};

#[cfg(target_os = "android")]
pub struct EngineImpl {
  pub egl_context: Option<Box<EglContext>>,
  pub program: Option<Program>,
}

#[cfg(target_os = "android")]
impl Default for EngineImpl {
  fn default() -> EngineImpl {
    EngineImpl {
      egl_context: None,
      program: None,
    }
  }
}

#[cfg(target_os = "linux")]
pub struct EngineImpl {
  pub window: XWindow,
  pub program: Program,
}

/// Field of view.
pub struct Fov {
  center_angle_degrees: f32,  // in xz plane, from (0, 0, -1).
}

impl Fov {
  fn inc_center_angle(&mut self, degrees: f32) {
    self.center_angle_degrees += degrees;
    if self.center_angle_degrees > 360.0 {
      self.center_angle_degrees -= 360.0;
    }
  }

  /// A view matrix, eye is at (p.x, p.y + 2.12, p.z), rotating in horizontal plane clockwise
  /// (thus the world is rotating counter-clockwise) and looking at
  /// (p.x + sin α, p.y + 2.12, p.z - cos α).
  fn view_matrix(&self, p: &Point3<i32>) -> Matrix4<f32> {
    let y = p.y as f32 + 2.12;  // 0.5 for half block under feet + 1.62 up to eye height.
    let (s, c) = self.center_angle_degrees.to_radians().sin_cos();

    let eye = Point3::new(p.x as f32, y, p.z as f32);
    // Start with α == 0, looking at (p.x, y, p.z - 1).
    let center = Point3::new(p.x as f32 + s, y, p.z as f32 - c);
    let up = Vector3::new(0.0, 1.0, 0.0);
    Matrix4::look_at(&eye, &center, &up)
  }
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  fov: Fov,
  /// GL projection matrix
  projection_matrix: Matrix4<f32>,
  /// Texture atlas.
  texture: Texture,
  world: World,
  buffers: HashMap<Chunk, Buffers>,
}

impl Engine {
  #[cfg(target_os = "android")]
  pub fn new() -> Engine {
    Engine {
      engine_impl: Default::default(),
      animating: false,
      fov: Fov {
        center_angle_degrees: 0.0,
      },
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: World::new(&Point2::new(0.0, 0.0), FAR_PLANE),
      buffers: HashMap::new(),
    }
  }

  #[cfg(target_os = "linux")]
  pub fn new(window: XWindow, program: Program) -> Engine {
    Engine {
      engine_impl: EngineImpl {
        window: window,
        program: program,
      },
      animating: false,
      fov: Fov {
        center_angle_degrees: 0.0,
      },
      projection_matrix: Matrix4::identity(),
      texture: Default::default(),
      world: World::new(&Point2::new(0.0, 0.0), FAR_PLANE),
      buffers: HashMap::new(),
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "android")]
  pub fn init(&mut self, egl_context: Box<EglContext>, texture_atlas_bytes: &[u8]) {
    self.engine_impl.egl_context = Some(egl_context);

    self.engine_impl.program = match Program::new() {
      Ok(p) => Some(p),
      Err(e) => panic!("Program failed: {:?}", e),
    };

    self.common_init(texture_atlas_bytes);

    if let Some(ref p) = self.engine_impl.program {
      p.set_texture_unit(0);
    }

    // Silly gymnastics to satisfy the borrow checker.
    let wh = if let Some(ref ec) = self.engine_impl.egl_context {
      Some((ec.width, ec.height))
    } else {
      None
    };
    if let Some((w, h)) = wh {
      self.set_viewport(w, h);
    }
  }

  /// Initialize the engine.
  #[cfg(target_os = "linux")]
  pub fn init(&mut self, texture_atlas_bytes: &[u8]) {
    self.common_init(texture_atlas_bytes);
    self.engine_impl.program.set_texture_unit(0);
  }

  fn common_init(&mut self, texture_atlas_bytes: &[u8]) {
    // Set the background clear color to sky blue.
    gl::clear_color(0.5, 0.69, 1.0, 1.0);

    // Enable reverse face culling.
    gl::enable(gl::CULL_FACE);
    // Enable depth test.
    gl::enable(gl::DEPTH_TEST);
    gl::depth_func(gl::LEQUAL);

    // Set up textures.
    self.texture = Engine::load_texture_atlas(texture_atlas_bytes);
    gl::active_texture(gl::TEXTURE0);
    gl::bind_texture_2d(self.texture);

    self.load_meshes();
  }

  #[cfg(target_os = "android")]
  fn load_meshes(&mut self) {
    let start_s = time::precise_time_s();
    log!("*** Loading meshes...");

    if let Some(ref mut p) = self.engine_impl.program {
      for (c, bs) in self.world.chunk_blocks() {
        let vertices = mesh::create_mesh_vertices(bs, &self.world);
        let buffers = p.upload_vertices(&vertices);
        let c = (*c).clone();
        self.buffers.insert(c, buffers);
      }
    }

    let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
    log!("*** Loaded meshes: {:.3}ms, {} chunks", spent_ms, self.buffers.len());
  }

  #[cfg(target_os = "linux")]
  fn load_meshes(&mut self) {
    let start_s = time::precise_time_s();
    log!("*** Loading meshes...");

    let p = &self.engine_impl.program;
    for (c, bs) in self.world.chunk_blocks() {
      let vertices = mesh::create_mesh_vertices(bs, &self.world);
      let buffers = p.upload_vertices(&vertices);
      let c = (*c).clone();
      self.buffers.insert(c, buffers);
    }

    let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
    log!("*** Loaded meshes: {:.3}ms, {} chunks", spent_ms, self.buffers.len());
  }

  pub fn set_viewport(&mut self, w: i32, h: i32) {
    gl::viewport(0, 0, w, h);
    self.projection_matrix = projection_matrix(w, h);
  }

  /// Load texture atlas from assets folder.
  fn load_texture_atlas(texture_atlas_bytes: &[u8]) -> Texture {
    let image = png::load_png_from_memory(texture_atlas_bytes)
      .unwrap_or_else(|s| panic!("load_png_from_memory() failed: {}", s));

    let pixels = match image.pixels {
      png::PixelsByColorType::RGBA8(v) => v,
      _ => {
        let color_type = match image.pixels {
            png::PixelsByColorType::K8(_) => "K8",
            png::PixelsByColorType::KA8(_) => "KA8",
            png::PixelsByColorType::RGB8(_) => "RGB8",
            png::PixelsByColorType::RGBA8(_) => panic!("Should not happen"),
        };
        panic!("Only RGBA8 image format supported, was: {}", color_type);
      }
    };

    let texture = gl::gen_texture();
    gl::bind_texture_2d(texture);
    gl::texture_2d_param(gl::TEXTURE_MIN_FILTER, gl::NEAREST_MIPMAP_LINEAR);
    gl::texture_2d_param(gl::TEXTURE_MAG_FILTER, gl::NEAREST);
    gl::texture_2d_param(gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE);
    gl::texture_2d_param(gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE);
    gl::texture_2d_image_rgba(image.width as i32, image.height as i32, &pixels);
    gl::generate_mipmap_2d();
    gl::bind_texture_2d(0);

    texture
  }

  /// Draw a frame.
  #[cfg(target_os = "android")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    match self.engine_impl.egl_context {
      None => return,  // No display.
      Some(ref egl_context) => {
        gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

        match self.engine_impl.program {
          Some(ref p) => {
            if let Some(e) = self.world.eye() {
              // Compute the composite mvp_matrix and send it to program.  Model matrix
              // is always identity so instead of MVP = P * V * M just do MVP = P * V.
              let mvp_matrix = self.projection_matrix * self.fov.view_matrix(&e);
              p.set_mvp_matrix(mvp_matrix);

              // Finally, draw the cube mesh.
              // TODO: Draw only meshes for only visible chunks within FOV.
              for bs in self.buffers.values() {
                p.bind_buffers(bs);
                gl::draw_elements_triangles_u16(bs.index_count);
                p.unbind_buffers();
              }
            }
          },
          None => panic!("Missing program, should never happen"),
        }

        egl_context.swap_buffers();
      }
    }
  }

  /// Draw a frame.
  #[cfg(target_os = "linux")]
  pub fn draw(&mut self) {
    if !self.animating {
      return;
    }

    gl::clear(gl::DEPTH_BUFFER_BIT | gl::COLOR_BUFFER_BIT);

    let p = &self.engine_impl.program;

    if let Some(e) = self.world.eye() {
      // Compute the composite mvp_matrix and send it to program.  Model matrix
      // is always identity so instead of MVP = P * V * M just do MVP = P * V.
      let mvp_matrix = self.projection_matrix * self.fov.view_matrix(&e);
      p.set_mvp_matrix(mvp_matrix);

      // Finally, draw the cube meshes for all chunks.
      // TODO: Draw only meshes for only visible chunks within FOV.
      for bs in self.buffers.values() {
        p.bind_buffers(bs);
        gl::draw_elements_triangles_u16(bs.index_count);
        p.unbind_buffers();
      }
    }

    self.engine_impl.window.swap_buffers();
    self.engine_impl.window.flush();
  }

  /// Update for time passed and draw a frame.
  pub fn update_draw(&mut self) {
    if self.animating {
      // Done processing events; draw next animation frame.
      // Do a complete rotation every 10 seconds, assuming 60 FPS.
      self.fov.inc_center_angle(360.0 / 600.0);

      // Drawing is throttled to the screen update rate, so there is no need to do timing here.
      self.draw();
    }
  }

  /// Terminate the engine.
  #[cfg(target_os = "android")]
  pub fn term(&mut self) {
    self.animating = false;
    // Drop the program and the EGL context.
    self.engine_impl = Default::default();
    log!("*** Renderer terminated");
  }

  /// Called when window gains input focus.
  pub fn gained_focus(&mut self) {
    self.animating = true;
  }

  /// Called when window loses input focus.
  pub fn lost_focus(&mut self) {
    self.animating = false;
  }

  #[cfg(target_os = "linux")]
  pub fn is_closed(&self) -> bool {
    self.engine_impl.window.is_closed()
  }

  #[cfg(target_os = "linux")]
  pub fn poll_events(&self) -> PollEventsIterator {
    self.engine_impl.window.poll_events()
  }
}

const NEAR_PLANE: f32 = 0.1;
const FAR_PLANE: f32 = 60.0;
const FIELD_OF_VIEW_DEGREES: f32 = 70.0;

/// Perspective projection matrix as frustum matrix.
fn projection_matrix(width: i32, height: i32) -> Matrix4<f32> {
  let inverse_aspect = height as f32 / width as f32;
  let field_of_view = FIELD_OF_VIEW_DEGREES.to_radians();

  let right = NEAR_PLANE * (field_of_view / 2.0).tan();
  let left = -right;
  let top = right * inverse_aspect;
  let bottom = -top;
  let near = NEAR_PLANE;
  let far = FAR_PLANE;
  cgmath::frustum(left, right, bottom, top, near, far)
}
<|endoftext|>


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

// TODO error_chain needs to be upgraded, it uses deprecated APIs.
#![allow(deprecated)]
#![allow(renamed_and_removed_lints)]

use std::boxed::Box;
use std::convert;
use std::error;
use std::io;
use std::process;

#[cfg(feature = "jsonwebtoken")]
use crate::jwt;
use futures::future;
use futures::Future;

error_chain! {
    foreign_links {
        Hyper(hyper::Error) #[cfg(feature = "hyper")];
        Io(io::Error);
        Lru(lru_disk_cache::Error);
        Json(serde_json::Error);
        Jwt(jwt::errors::Error) #[cfg(feature = "jsonwebtoken")];
        Openssl(openssl::error::ErrorStack) #[cfg(feature = "openssl")];
        Base64Decode(base64::DecodeError);
        Bincode(bincode::Error);
        Memcached(memcached::proto::Error) #[cfg(feature = "memcached")];
        Redis(redis::RedisError) #[cfg(feature = "redis")];
        Reqwest(reqwest::Error) #[cfg(feature = "reqwest")];
        StrFromUtf8(::std::string::FromUtf8Error) #[cfg(feature = "gcs")];
        TempfilePersist(tempfile::PersistError);
        WalkDir(walkdir::Error);
        Timer(tokio_timer::Error);
    }

    errors {
        #[cfg(feature = "hyper")]
        BadHTTPStatus(status: hyper::StatusCode) {
            description("failed to get a successful HTTP status")
            display("didn't get a successful HTTP status, got `{}`", status)
        }
        HttpClientError(msg: String) {
            display("didn't get a successful HTTP status, got `{}`", msg)
        }
        ProcessError(output: process::Output) {
            display("{}", String::from_utf8_lossy(&output.stderr))
        }
        Which(err: which::Error) {
            display("{}", err)
        }
    }
}

impl From<which::Error> for Error {
    fn from(err: which::Error) -> Self {
        Error::from(ErrorKind::Which(err))
    }
}

#[cfg(feature = "gcs")]
impl From<chrono::ParseError> for Error {
    fn from(err: chrono::ParseError) -> Self {
        Error::from(err.to_string())
    }
}

pub type SFuture<T> = Box<dyn Future<Item = T, Error = Error>>;
pub type SFutureSend<T> = Box<dyn Future<Item = T, Error = Error> + Send>;

pub trait FutureChainErr<T> {
    fn chain_err<F, E>(self, callback: F) -> SFuture<T>
    where
        F: FnOnce() -> E + 'static,
        E: Into<ErrorKind>;
}

impl<F> FutureChainErr<F::Item> for F
where
    F: Future + 'static,
    F::Error: error::Error + Send + 'static,
{
    fn chain_err<C, E>(self, callback: C) -> SFuture<F::Item>
    where
        C: FnOnce() -> E + 'static,
        E: Into<ErrorKind>,
    {
        Box::new(self.then(|r| r.chain_err(callback)))
    }
}

/// Like `try`, but returns an SFuture instead of a Result.
macro_rules! ftry {
    ($e:expr) => {
        match $e {
            Ok(v) => v,
            Err(e) => return Box::new($crate::futures::future::err(e.into())) as SFuture<_>,
        }
    };
}

#[cfg(any(feature = "dist-client", feature = "dist-server"))]
macro_rules! ftry_send {
    ($e:expr) => {
        match $e {
            Ok(v) => v,
            Err(e) => return Box::new($crate::futures::future::err(e.into())) as SFutureSend<_>,
        }
    };
}

pub fn f_res<T, E: convert::Into<Error>>(t: ::std::result::Result<T, E>) -> SFuture<T>
where
    T: 'static,
{
    Box::new(future::result(t.map_err(Into::into)))
}

pub fn f_ok<T>(t: T) -> SFuture<T>
where
    T: 'static,
{
    Box::new(future::ok(t))
}

pub fn f_err<T, E>(e: E) -> SFuture<T>
where
    T: 'static,
    E: Into<Error>,
{
    Box::new(future::err(e.into()))
}
<commit_msg>Remove some unneeded error kinds.<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use futures::future;
use futures::Future;
use std::boxed::Box;
use std::convert;
use std::error;
use std::io;
use std::process;

error_chain! {
    foreign_links {
        Hyper(hyper::Error) #[cfg(feature = "hyper")];
        Io(io::Error);
        Lru(lru_disk_cache::Error);
        Json(serde_json::Error);
        Openssl(openssl::error::ErrorStack) #[cfg(feature = "openssl")];
        Bincode(bincode::Error);
        Memcached(memcached::proto::Error) #[cfg(feature = "memcached")];
        Redis(redis::RedisError) #[cfg(feature = "redis")];
        Reqwest(reqwest::Error) #[cfg(feature = "reqwest")];
        StrFromUtf8(::std::string::FromUtf8Error) #[cfg(feature = "gcs")];
        TempfilePersist(tempfile::PersistError);
        WalkDir(walkdir::Error);
        Timer(tokio_timer::Error);
    }

    errors {
        #[cfg(feature = "hyper")]
        BadHTTPStatus(status: hyper::StatusCode) {
            description("failed to get a successful HTTP status")
            display("didn't get a successful HTTP status, got `{}`", status)
        }
        HttpClientError(msg: String) {
            display("didn't get a successful HTTP status, got `{}`", msg)
        }
        ProcessError(output: process::Output) {
            display("{}", String::from_utf8_lossy(&output.stderr))
        }
        Which(err: which::Error) {
            display("{}", err)
        }
    }
}

impl From<which::Error> for Error {
    fn from(err: which::Error) -> Self {
        Error::from(ErrorKind::Which(err))
    }
}

#[cfg(feature = "gcs")]
impl From<chrono::ParseError> for Error {
    fn from(err: chrono::ParseError) -> Self {
        Error::from(err.to_string())
    }
}

pub type SFuture<T> = Box<dyn Future<Item = T, Error = Error>>;
pub type SFutureSend<T> = Box<dyn Future<Item = T, Error = Error> + Send>;

pub trait FutureChainErr<T> {
    fn chain_err<F, E>(self, callback: F) -> SFuture<T>
    where
        F: FnOnce() -> E + 'static,
        E: Into<ErrorKind>;
}

impl<F> FutureChainErr<F::Item> for F
where
    F: Future + 'static,
    F::Error: error::Error + Send + 'static,
{
    fn chain_err<C, E>(self, callback: C) -> SFuture<F::Item>
    where
        C: FnOnce() -> E + 'static,
        E: Into<ErrorKind>,
    {
        Box::new(self.then(|r| r.chain_err(callback)))
    }
}

/// Like `try`, but returns an SFuture instead of a Result.
macro_rules! ftry {
    ($e:expr) => {
        match $e {
            Ok(v) => v,
            Err(e) => return Box::new($crate::futures::future::err(e.into())) as SFuture<_>,
        }
    };
}

#[cfg(any(feature = "dist-client", feature = "dist-server"))]
macro_rules! ftry_send {
    ($e:expr) => {
        match $e {
            Ok(v) => v,
            Err(e) => return Box::new($crate::futures::future::err(e.into())) as SFutureSend<_>,
        }
    };
}

pub fn f_res<T, E: convert::Into<Error>>(t: ::std::result::Result<T, E>) -> SFuture<T>
where
    T: 'static,
{
    Box::new(future::result(t.map_err(Into::into)))
}

pub fn f_ok<T>(t: T) -> SFuture<T>
where
    T: 'static,
{
    Box::new(future::ok(t))
}

pub fn f_err<T, E>(e: E) -> SFuture<T>
where
    T: 'static,
    E: Into<Error>,
{
    Box::new(future::err(e.into()))
}
<|endoftext|>


<commit_before>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use retry::retry;
use record::Record;
use record::FluentError;
use retry_conf::RetryConf;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
    conf: RetryConf,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: RetryConf::new(),
        }
    }

    pub fn new_with_conf<T>(addr: A, tag: T, conf: RetryConf) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: conf,
        }
    }

    /// Post record into Fluentd. Without time version.
    pub fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    pub fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag.clone(), time, record);
        let message = try!(record.make_forwardable_json());
        let addr = self.addr;
        let (max, timeout) = self.conf.build();
        match retry(max, timeout, || Fluent::closure_send_data(&addr, message.clone()), |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }

    fn closure_send_data(addr: &A, message: String) -> Result<(), FluentError> {
        let mut stream = try!(net::TcpStream::connect(addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature="fluentd")]
    use time;
    use retry_conf::RetryConf;

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
            conf: RetryConf::new(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time);
        let is_ok = match result {
            Ok(()) => true,
            _ => false,
        };
        assert_eq!(true, is_ok);
    }
}
<commit_msg>fluent: Use is_ok() as treating boolean in assertion<commit_after>use std::net::ToSocketAddrs;
use std::convert::AsRef;
use std::net;
use std::io::Write;
use rustc_serialize::Encodable;
use time;
use retry::retry;
use record::Record;
use record::FluentError;
use retry_conf::RetryConf;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fluent
    where A: ToSocketAddrs
{
    addr: A,
    tag: String,
    conf: RetryConf,
}

impl Fluent {
    /// Create Fluent type.
    ///
    /// ### Usage
    ///
    /// ```
    /// use fruently::fluent::Fluent;
    /// let fruently_with_str_tag = Fluent::new("0.0.0.0:24224", "test");
    /// let fruently_with_string_tag = Fluent::new("0.0.0.0:24224", "test".to_string());
    /// ```
    pub fn new<T>(addr: A, tag: T) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: RetryConf::new(),
        }
    }

    pub fn new_with_conf<T>(addr: A, tag: T, conf: RetryConf) -> Fluent
        where T: AsRef<str>
    {
        Fluent {
            addr: addr,
            tag: format!("{}", tag.as_ref()),
            conf: conf,
        }
    }

    /// Post record into Fluentd. Without time version.
    pub fn post<T>(self, record: T) -> Result<(), FluentError>
        where T: Encodable
    {
        let time = time::now();
        return self.post_with_time(record, time);
    }

    /// Post record into Fluentd. With time version.
    pub fn post_with_time<T>(self, record: T, time: time::Tm) -> Result<(), FluentError>
        where T: Encodable
    {
        let record = Record::new(self.tag.clone(), time, record);
        let message = try!(record.make_forwardable_json());
        let addr = self.addr;
        let (max, timeout) = self.conf.build();
        match retry(max, timeout, || Fluent::closure_send_data(&addr, message.clone()), |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }

    fn closure_send_data(addr: &A, message: String) -> Result<(), FluentError> {
        let mut stream = try!(net::TcpStream::connect(addr));
        let result = stream.write(&message.into_bytes());
        drop(stream);

        match result {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[cfg(feature="fluentd")]
    use time;
    use retry_conf::RetryConf;

    #[test]
    fn create_fruently() {
        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let expected = Fluent {
            addr: "0.0.0.0:24224",
            tag: "test".to_string(),
            conf: RetryConf::new(),
        };
        assert_eq!(expected, fruently);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let result = fruently.post(obj).is_ok();
        assert_eq!(true, result);
    }

    #[test]
    #[cfg(feature="fluentd")]
    fn test_post_with_time() {
        use std::collections::HashMap;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("hey".to_string(), "Rust!".to_string());
        let time = time::now();
        let result = fruently.post_with_time(obj, time).is_ok();
        assert_eq!(true, result);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate getopts;
extern crate rocket;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate rocket_contrib;

extern crate pombase;

use std::sync::Mutex;
use std::process;
use std::env;
use std::path::{Path, PathBuf};

use getopts::Options;

use rocket_contrib::{Json, Value};

use rocket::response::NamedFile;

use pombase::api::query::Query;
use pombase::api::result::QueryAPIResult;
use pombase::api::search::Search;
use pombase::api::query_exec::QueryExec;
use pombase::api::server_data::ServerData;
use pombase::web::data::SolrTermSummary;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

struct StaticFileState {
    web_root_dir: String,
}

// try the path, then try path + ".json", then default to loading the Angular app
// from /index.html
#[get("/<path..>", rank=3)]
fn get_misc(path: PathBuf, state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    print!("full_path 1: {:?}\n", path);
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    print!("web_root_dir: {:?}\n", web_root_dir);
    let root_dir_path = Path::new("/").join(web_root_dir);
    print!("root_dir_path: {:?}\n", root_dir_path);
    let full_path = root_dir_path.join(path);
    print!("full_path 1: {:?}\n", full_path);
    if full_path.exists() {
        NamedFile::open(full_path).ok()
    } else {
        print!("full_path: {:?}\n", full_path);
        let mut json_path_str = full_path.to_str().unwrap().to_owned();
        json_path_str += ".json";
        let json_path: PathBuf = json_path_str.into();

        if json_path.exists() {
            print!("exists: {:?}\n", json_path);
            NamedFile::open(json_path).ok()
        } else {
            print!("not exists: {:?}\n", json_path);
            NamedFile::open(root_dir_path.join("index.html")).ok()
        }
    }
}

#[get("/", rank=1)]
fn get_index(state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[post("/api/v1/dataset/latest/query", rank=1, data="<q>", format = "application/json")]
fn query_post(q: Json<Query>, state: rocket::State<Mutex<QueryExec>>)
              -> Option<Json<QueryAPIResult>>
{
    let query_exec = state.lock().expect("failed to lock");
    Some(Json(query_exec.exec(&q.into_inner())))
}

#[get ("/reload")]
fn reload(state: rocket::State<Mutex<QueryExec>>) {
    let mut query_exec = state.lock().expect("failed to lock");
    print!("reloading ...\n");
    query_exec.reload();
    print!("... done\n");
}

#[derive(Serialize, Debug)]
struct CompletionResponse {
    status: String,
    matches: Vec<SolrTermSummary>,
}

#[get ("/api/v1/dataset/latest/complete/<cv_name>/<q>", rank=1)]
fn complete(cv_name: String, q: String, state: rocket::State<Mutex<Search>>)
              -> Option<Json<CompletionResponse>>
{
    let search = state.lock().expect("failed to lock");
    let res = search.term_complete(&cv_name, &q);

    let completion_response =
        match res {
            Ok(matches) => {
                CompletionResponse {
                    status: "Ok".to_owned(),
                    matches: matches,
                }
            },
            Err(err) => {
                println!("{:?}", err);
                CompletionResponse {
                    status: "Error".to_owned(),
                    matches: vec![],
                }
            },
        };

    Some(Json(completion_response))
}

#[get ("/ping", rank=1)]
fn ping() -> Option<String> {
    Some(String::from("OK") + " " + PKG_NAME + " " + VERSION)
}

#[error(404)]
fn not_found() -> Json<Value> {
    Json(json!({
        "status": "error",
        "reason": "Resource was not found."
    }))
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("m", "search-maps", "Search data", "MAPS_JSON_FILE");
    opts.optopt("s", "gene-subsets", "Gene subset data", "SUBSETS_JSON_FILE");
    opts.optopt("w", "web-root-dir", "Root web data directory", "WEB_ROOT_DIR");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("search-maps") {
        print!("no --search-maps|-m option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("gene-subsets") {
        print!("no --gene-subsets|-s option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("web-root-dir") {
        print!("no --web-root-dir|-w option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let search_maps_filename = matches.opt_str("m").unwrap();
    let gene_subsets_filename = matches.opt_str("s").unwrap();
    println!("Reading data files ...");

    let config_file_name = matches.opt_str("c").unwrap();
    let server_data = ServerData::new(&config_file_name, &search_maps_filename,
                                      &gene_subsets_filename);
    let query_exec = QueryExec::new(server_data);
    let searcher = Search::new("http://localhost:8983/solr".to_owned());

    let web_root_dir = matches.opt_str("w").unwrap();
    let static_file_state = StaticFileState {
        web_root_dir: web_root_dir,
    };

    println!("Starting server ...");
    rocket::ignite()
        .mount("/", routes![get_index, get_misc, query_post, reload, complete, ping])
        .catch(errors![not_found])
        .manage(Mutex::new(query_exec))
        .manage(Mutex::new(searcher))
        .manage(Mutex::new(static_file_state))
        .launch();
}
<commit_msg>Simplify logic of get_misc() and remove debug code<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate getopts;
extern crate rocket;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate rocket_contrib;

extern crate pombase;

use std::sync::Mutex;
use std::process;
use std::env;
use std::path::{Path, PathBuf};

use getopts::Options;

use rocket_contrib::{Json, Value};

use rocket::response::NamedFile;

use pombase::api::query::Query;
use pombase::api::result::QueryAPIResult;
use pombase::api::search::Search;
use pombase::api::query_exec::QueryExec;
use pombase::api::server_data::ServerData;
use pombase::web::data::SolrTermSummary;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

struct StaticFileState {
    web_root_dir: String,
}

// try the path, then try path + ".json", then default to loading the Angular app
// from /index.html
#[get("/<path..>", rank=3)]
fn get_misc(path: PathBuf, state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    let full_path = root_dir_path.join(path);
    if full_path.exists() {
        return NamedFile::open(full_path).ok();
    }

    let mut json_path_str = full_path.to_str().unwrap().to_owned();
    json_path_str += ".json";
    let json_path: PathBuf = json_path_str.into();

    if json_path.exists() {
        return NamedFile::open(json_path).ok();
    }

    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[get("/", rank=1)]
fn get_index(state: rocket::State<Mutex<StaticFileState>>) -> Option<NamedFile> {
    let web_root_dir = &state.lock().expect("failed to lock").web_root_dir;
    let root_dir_path = Path::new("/").join(web_root_dir);
    NamedFile::open(root_dir_path.join("index.html")).ok()
}

#[post("/api/v1/dataset/latest/query", rank=1, data="<q>", format = "application/json")]
fn query_post(q: Json<Query>, state: rocket::State<Mutex<QueryExec>>)
              -> Option<Json<QueryAPIResult>>
{
    let query_exec = state.lock().expect("failed to lock");
    Some(Json(query_exec.exec(&q.into_inner())))
}

#[get ("/reload")]
fn reload(state: rocket::State<Mutex<QueryExec>>) {
    let mut query_exec = state.lock().expect("failed to lock");
    print!("reloading ...\n");
    query_exec.reload();
    print!("... done\n");
}

#[derive(Serialize, Debug)]
struct CompletionResponse {
    status: String,
    matches: Vec<SolrTermSummary>,
}

#[get ("/api/v1/dataset/latest/complete/<cv_name>/<q>", rank=1)]
fn complete(cv_name: String, q: String, state: rocket::State<Mutex<Search>>)
              -> Option<Json<CompletionResponse>>
{
    let search = state.lock().expect("failed to lock");
    let res = search.term_complete(&cv_name, &q);

    let completion_response =
        match res {
            Ok(matches) => {
                CompletionResponse {
                    status: "Ok".to_owned(),
                    matches: matches,
                }
            },
            Err(err) => {
                println!("{:?}", err);
                CompletionResponse {
                    status: "Error".to_owned(),
                    matches: vec![],
                }
            },
        };

    Some(Json(completion_response))
}

#[get ("/ping", rank=1)]
fn ping() -> Option<String> {
    Some(String::from("OK") + " " + PKG_NAME + " " + VERSION)
}

#[error(404)]
fn not_found() -> Json<Value> {
    Json(json!({
        "status": "error",
        "reason": "Resource was not found."
    }))
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("m", "search-maps", "Search data", "MAPS_JSON_FILE");
    opts.optopt("s", "gene-subsets", "Gene subset data", "SUBSETS_JSON_FILE");
    opts.optopt("w", "web-root-dir", "Root web data directory", "WEB_ROOT_DIR");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("search-maps") {
        print!("no --search-maps|-m option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("gene-subsets") {
        print!("no --gene-subsets|-s option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("web-root-dir") {
        print!("no --web-root-dir|-w option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let search_maps_filename = matches.opt_str("m").unwrap();
    let gene_subsets_filename = matches.opt_str("s").unwrap();
    println!("Reading data files ...");

    let config_file_name = matches.opt_str("c").unwrap();
    let server_data = ServerData::new(&config_file_name, &search_maps_filename,
                                      &gene_subsets_filename);
    let query_exec = QueryExec::new(server_data);
    let searcher = Search::new("http://localhost:8983/solr".to_owned());

    let web_root_dir = matches.opt_str("w").unwrap();
    let static_file_state = StaticFileState {
        web_root_dir: web_root_dir,
    };

    println!("Starting server ...");
    rocket::ignite()
        .mount("/", routes![get_index, get_misc, query_post, reload, complete, ping])
        .catch(errors![not_found])
        .manage(Mutex::new(query_exec))
        .manage(Mutex::new(searcher))
        .manage(Mutex::new(static_file_state))
        .launch();
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use super::address::SBAddress;
use super::breakpoint::SBBreakpoint;
use super::stream::SBStream;
use super::{lldb_addr_t, DescriptionLevel};
use sys;

/// One unique instance (by address) of a logical breakpoint.
///
/// A breakpoint location is defined by the breakpoint that
/// produces it, and the address that resulted in this
/// particular instantiation.  Each breakpoint location has
/// its settable options.
///
/// `SBBreakpoint` contains `SBBreakpointLocation`(s).
/// See [`SBBreakpoint`] for retrieval of an `SBBreakpointLocation`
/// from an `SBBreakpoint`.
///
/// [`SBBreakpoint`]: struct.SBBreakpoint.html
pub struct SBBreakpointLocation {
    /// The underlying raw `SBBreakpointLocationRef`.
    pub raw: sys::SBBreakpointLocationRef,
}

impl SBBreakpointLocation {
    /// Construct a new `SBBreakpointLocation`.
    pub fn wrap(raw: sys::SBBreakpointLocationRef) -> SBBreakpointLocation {
        SBBreakpointLocation { raw }
    }

    /// Construct a new `Some(SBBreakpointLocation)` or `None`.
    pub fn maybe_wrap(raw: sys::SBBreakpointLocationRef) -> Option<SBBreakpointLocation> {
        if unsafe { sys::SBBreakpointLocationIsValid(raw) != 0 } {
            Some(SBBreakpointLocation { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBBreakpointLocation` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBBreakpointLocationIsValid(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn id(&self) -> i32 {
        unsafe { sys::SBBreakpointLocationGetID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn address(&self) -> Option<SBAddress> {
        SBAddress::maybe_wrap(unsafe { sys::SBBreakpointLocationGetAddress(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn load_address(&self) -> lldb_addr_t {
        unsafe { sys::SBBreakpointLocationGetLoadAddress(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn is_enabled(&self) -> bool {
        unsafe { sys::SBBreakpointLocationIsEnabled(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn set_enabled(&self, enabled: bool) {
        unsafe { sys::SBBreakpointLocationSetEnabled(self.raw, enabled as u8) }
    }

    #[allow(missing_docs)]
    pub fn ignore_count(&self) -> u32 {
        unsafe { sys::SBBreakpointLocationGetIgnoreCount(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_ignore_count(&self, count: u32) {
        unsafe { sys::SBBreakpointLocationSetIgnoreCount(self.raw, count) }
    }

    #[allow(missing_docs)]
    pub fn is_resolved(&self) -> bool {
        unsafe { sys::SBBreakpointLocationIsResolved(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn breakpoint(&self) -> SBBreakpoint {
        SBBreakpoint::wrap(unsafe { sys::SBBreakpointLocationGetBreakpoint(self.raw) })
    }
}

impl fmt::Debug for SBBreakpointLocation {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe {
            sys::SBBreakpointLocationGetDescription(self.raw, stream.raw, DescriptionLevel::Brief)
        };
        write!(fmt, "SBBreakpointLocation {{ {} }}", stream.data())
    }
}

impl Drop for SBBreakpointLocation {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBBreakpointLocation(self.raw) };
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBBreakpointLocation: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm) This should be i32
    field id() -> i64 {
        self.id() as i64
    }

    field address() -> Option<SBAddress> {
        self.address()
    }

    // TODO(bm) This should be u64
    field load_address() -> i64 {
        self.load_address() as i64
    }

    field is_enabled() -> bool {
        self.is_enabled()
    }

    // TODO(bm) This should be u32
    field ignore_count() -> i64 {
        self.ignore_count() as i64
    }

    field is_resolved() -> bool {
        self.is_resolved()
    }

    field breakpoint() -> SBBreakpoint {
        self.breakpoint()
    }
});
<commit_msg>Add binding for SBBreakpointLocation::hit_count().<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use super::address::SBAddress;
use super::breakpoint::SBBreakpoint;
use super::stream::SBStream;
use super::{lldb_addr_t, DescriptionLevel};
use sys;

/// One unique instance (by address) of a logical breakpoint.
///
/// A breakpoint location is defined by the breakpoint that
/// produces it, and the address that resulted in this
/// particular instantiation.  Each breakpoint location has
/// its settable options.
///
/// `SBBreakpoint` contains `SBBreakpointLocation`(s).
/// See [`SBBreakpoint`] for retrieval of an `SBBreakpointLocation`
/// from an `SBBreakpoint`.
///
/// [`SBBreakpoint`]: struct.SBBreakpoint.html
pub struct SBBreakpointLocation {
    /// The underlying raw `SBBreakpointLocationRef`.
    pub raw: sys::SBBreakpointLocationRef,
}

impl SBBreakpointLocation {
    /// Construct a new `SBBreakpointLocation`.
    pub fn wrap(raw: sys::SBBreakpointLocationRef) -> SBBreakpointLocation {
        SBBreakpointLocation { raw }
    }

    /// Construct a new `Some(SBBreakpointLocation)` or `None`.
    pub fn maybe_wrap(raw: sys::SBBreakpointLocationRef) -> Option<SBBreakpointLocation> {
        if unsafe { sys::SBBreakpointLocationIsValid(raw) != 0 } {
            Some(SBBreakpointLocation { raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBBreakpointLocation` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBBreakpointLocationIsValid(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn id(&self) -> i32 {
        unsafe { sys::SBBreakpointLocationGetID(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn address(&self) -> Option<SBAddress> {
        SBAddress::maybe_wrap(unsafe { sys::SBBreakpointLocationGetAddress(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn load_address(&self) -> lldb_addr_t {
        unsafe { sys::SBBreakpointLocationGetLoadAddress(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn is_enabled(&self) -> bool {
        unsafe { sys::SBBreakpointLocationIsEnabled(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn set_enabled(&self, enabled: bool) {
        unsafe { sys::SBBreakpointLocationSetEnabled(self.raw, enabled as u8) }
    }

    #[allow(missing_docs)]
    pub fn hit_count(&self) -> u32 {
        unsafe { sys::SBBreakpointLocationGetHitCount(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn ignore_count(&self) -> u32 {
        unsafe { sys::SBBreakpointLocationGetIgnoreCount(self.raw) }
    }

    #[allow(missing_docs)]
    pub fn set_ignore_count(&self, count: u32) {
        unsafe { sys::SBBreakpointLocationSetIgnoreCount(self.raw, count) }
    }

    #[allow(missing_docs)]
    pub fn is_resolved(&self) -> bool {
        unsafe { sys::SBBreakpointLocationIsResolved(self.raw) != 0 }
    }

    #[allow(missing_docs)]
    pub fn breakpoint(&self) -> SBBreakpoint {
        SBBreakpoint::wrap(unsafe { sys::SBBreakpointLocationGetBreakpoint(self.raw) })
    }
}

impl fmt::Debug for SBBreakpointLocation {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe {
            sys::SBBreakpointLocationGetDescription(self.raw, stream.raw, DescriptionLevel::Brief)
        };
        write!(fmt, "SBBreakpointLocation {{ {} }}", stream.data())
    }
}

impl Drop for SBBreakpointLocation {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBBreakpointLocation(self.raw) };
    }
}

#[cfg(feature = "graphql")]
graphql_object!(SBBreakpointLocation: super::debugger::SBDebugger | &self | {
    field is_valid() -> bool {
        self.is_valid()
    }

    // TODO(bm) This should be i32
    field id() -> i64 {
        self.id() as i64
    }

    field address() -> Option<SBAddress> {
        self.address()
    }

    // TODO(bm) This should be u64
    field load_address() -> i64 {
        self.load_address() as i64
    }

    field is_enabled() -> bool {
        self.is_enabled()
    }

    // TODO(bm) This should be u32
    field ignore_count() -> i64 {
        self.ignore_count() as i64
    }

    field is_resolved() -> bool {
        self.is_resolved()
    }

    field breakpoint() -> SBBreakpoint {
        self.breakpoint()
    }
});
<|endoftext|>


<commit_before>use anyhow::Error;

use crate::util::errors::{CargoResult, HttpNot200};
use crate::util::Config;

pub struct Retry<'a> {
    config: &'a Config,
    remaining: u32,
}

impl<'a> Retry<'a> {
    pub fn new(config: &'a Config) -> CargoResult<Retry<'a>> {
        Ok(Retry {
            config,
            remaining: config.net_config()?.retry.unwrap_or(2),
        })
    }

    pub fn r#try<T>(&mut self, f: impl FnOnce() -> CargoResult<T>) -> CargoResult<Option<T>> {
        match f() {
            Err(ref e) if maybe_spurious(e) && self.remaining > 0 => {
                let msg = format!(
                    "spurious network error ({} tries remaining): {}",
                    self.remaining,
                    e.root_cause(),
                );
                self.config.shell().warn(msg)?;
                self.remaining -= 1;
                Ok(None)
            }
            other => other.map(Some),
        }
    }
}

fn maybe_spurious(err: &Error) -> bool {
    if let Some(git_err) = err.downcast_ref::<git2::Error>() {
        match git_err.class() {
            git2::ErrorClass::Net | git2::ErrorClass::Os => return true,
            _ => (),
        }
    }
    if let Some(curl_err) = err.downcast_ref::<curl::Error>() {
        if curl_err.is_couldnt_connect()
            || curl_err.is_couldnt_resolve_proxy()
            || curl_err.is_couldnt_resolve_host()
            || curl_err.is_operation_timedout()
            || curl_err.is_recv_error()
            || curl_err.is_http2_error()
            || curl_err.is_http2_stream_error()
            || curl_err.is_ssl_connect_error()
            || curl_err.is_partial_file()
        {
            return true;
        }
    }
    if let Some(not_200) = err.downcast_ref::<HttpNot200>() {
        if 500 <= not_200.code && not_200.code < 600 {
            return true;
        }
    }
    false
}

/// Wrapper method for network call retry logic.
///
/// Retry counts provided by Config object `net.retry`. Config shell outputs
/// a warning on per retry.
///
/// Closure must return a `CargoResult`.
///
/// # Examples
///
/// ```
/// # use crate::cargo::util::{CargoResult, Config};
/// # let download_something = || return Ok(());
/// # let config = Config::default().unwrap();
/// use cargo::util::network;
/// let cargo_result = network::with_retry(&config, || download_something());
/// ```
pub fn with_retry<T, F>(config: &Config, mut callback: F) -> CargoResult<T>
where
    F: FnMut() -> CargoResult<T>,
{
    let mut retry = Retry::new(config)?;
    loop {
        if let Some(ret) = retry.r#try(&mut callback)? {
            return Ok(ret);
        }
    }
}

#[test]
fn with_retry_repeats_the_call_then_works() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    let error1 = HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    }
    .into();
    let error2 = HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    }
    .into();
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn with_retry_finds_nested_spurious_errors() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    //String error messages are not considered spurious
    let error1 = anyhow::Error::from(HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    });
    let error1 = anyhow::Error::from(error1.context("A non-spurious wrapping err"));
    let error2 = anyhow::Error::from(HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    });
    let error2 = anyhow::Error::from(error2.context("A second chained error"));
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn curle_http2_stream_is_spurious() {
    let code = curl_sys::CURLE_HTTP2_STREAM;
    let err = curl::Error::new(code);
    assert!(maybe_spurious(&err.into()));
}
<commit_msg>Auto merge of #8520 - alexcrichton:zlib-spurious, r=ehuss<commit_after>use anyhow::Error;

use crate::util::errors::{CargoResult, HttpNot200};
use crate::util::Config;

pub struct Retry<'a> {
    config: &'a Config,
    remaining: u32,
}

impl<'a> Retry<'a> {
    pub fn new(config: &'a Config) -> CargoResult<Retry<'a>> {
        Ok(Retry {
            config,
            remaining: config.net_config()?.retry.unwrap_or(2),
        })
    }

    pub fn r#try<T>(&mut self, f: impl FnOnce() -> CargoResult<T>) -> CargoResult<Option<T>> {
        match f() {
            Err(ref e) if maybe_spurious(e) && self.remaining > 0 => {
                let msg = format!(
                    "spurious network error ({} tries remaining): {}",
                    self.remaining,
                    e.root_cause(),
                );
                self.config.shell().warn(msg)?;
                self.remaining -= 1;
                Ok(None)
            }
            other => other.map(Some),
        }
    }
}

fn maybe_spurious(err: &Error) -> bool {
    if let Some(git_err) = err.downcast_ref::<git2::Error>() {
        match git_err.class() {
            git2::ErrorClass::Net | git2::ErrorClass::Os | git2::ErrorClass::Zlib => return true,
            _ => (),
        }
    }
    if let Some(curl_err) = err.downcast_ref::<curl::Error>() {
        if curl_err.is_couldnt_connect()
            || curl_err.is_couldnt_resolve_proxy()
            || curl_err.is_couldnt_resolve_host()
            || curl_err.is_operation_timedout()
            || curl_err.is_recv_error()
            || curl_err.is_http2_error()
            || curl_err.is_http2_stream_error()
            || curl_err.is_ssl_connect_error()
            || curl_err.is_partial_file()
        {
            return true;
        }
    }
    if let Some(not_200) = err.downcast_ref::<HttpNot200>() {
        if 500 <= not_200.code && not_200.code < 600 {
            return true;
        }
    }
    false
}

/// Wrapper method for network call retry logic.
///
/// Retry counts provided by Config object `net.retry`. Config shell outputs
/// a warning on per retry.
///
/// Closure must return a `CargoResult`.
///
/// # Examples
///
/// ```
/// # use crate::cargo::util::{CargoResult, Config};
/// # let download_something = || return Ok(());
/// # let config = Config::default().unwrap();
/// use cargo::util::network;
/// let cargo_result = network::with_retry(&config, || download_something());
/// ```
pub fn with_retry<T, F>(config: &Config, mut callback: F) -> CargoResult<T>
where
    F: FnMut() -> CargoResult<T>,
{
    let mut retry = Retry::new(config)?;
    loop {
        if let Some(ret) = retry.r#try(&mut callback)? {
            return Ok(ret);
        }
    }
}

#[test]
fn with_retry_repeats_the_call_then_works() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    let error1 = HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    }
    .into();
    let error2 = HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    }
    .into();
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn with_retry_finds_nested_spurious_errors() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    //String error messages are not considered spurious
    let error1 = anyhow::Error::from(HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    });
    let error1 = anyhow::Error::from(error1.context("A non-spurious wrapping err"));
    let error2 = anyhow::Error::from(HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    });
    let error2 = anyhow::Error::from(error2.context("A second chained error"));
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn curle_http2_stream_is_spurious() {
    let code = curl_sys::CURLE_HTTP2_STREAM;
    let err = curl::Error::new(code);
    assert!(maybe_spurious(&err.into()));
}
<|endoftext|>


<commit_before>use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule, LibRule};

pub fn cli() -> App {
    subcommand("fix")
        .about("Automatically fix lint warnings reported by rustc")
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg_package_spec(
            "Package(s) to fix",
            "Fix all packages in the workspace",
            "Exclude packages from the fixes",
        )
        .arg_jobs()
        .arg_targets_all(
            "Fix only this package's library",
            "Fix only the specified binary",
            "Fix all binaries",
            "Fix only the specified example",
            "Fix all examples",
            "Fix only the specified test target",
            "Fix all tests",
            "Fix only the specified bench target",
            "Fix all benches",
            "Fix all targets (default)",
        )
        .arg_release("Fix artifacts in release mode, with optimizations")
        .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
        .arg_features()
        .arg_target_triple("Fix for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .arg(
            Arg::with_name("broken-code")
                .long("broken-code")
                .help("Fix code even if it already has compiler errors"),
        )
        .arg(
            Arg::with_name("edition")
                .long("edition")
                .help("Fix in preparation for the next edition"),
        )
        .arg(
            // This is a deprecated argument, we'll want to phase it out
            // eventually.
            Arg::with_name("prepare-for")
                .long("prepare-for")
                .help("Fix warnings in preparation of an edition upgrade")
                .takes_value(true)
                .possible_values(&["2018"])
                .conflicts_with("edition")
                .hidden(true),
        )
        .arg(
            Arg::with_name("idioms")
                .long("edition-idioms")
                .help("Fix warnings to migrate to the idioms of an edition"),
        )
        .arg(
            Arg::with_name("allow-no-vcs")
                .long("allow-no-vcs")
                .help("Fix code even if a VCS was not detected"),
        )
        .arg(
            Arg::with_name("allow-dirty")
                .long("allow-dirty")
                .help("Fix code even if the working directory is dirty"),
        )
        .arg(
            Arg::with_name("allow-staged")
                .long("allow-staged")
                .help("Fix code even if the working directory has staged changes"),
        )
        .arg(
            Arg::with_name("clippy")
                .long("clippy")
                .help("Get fix suggestions from clippy instead of rustc")
                .hidden(true),
        )
        .after_help(
            "\
This Cargo subcommand will automatically take rustc's suggestions from
diagnostics like warnings and apply them to your source code. This is intended
to help automate tasks that rustc itself already knows how to tell you to fix!
The `cargo fix` subcommand is also being developed for the Rust 2018 edition
to provide code the ability to easily opt-in to the new edition without having
to worry about any breakage.

Executing `cargo fix` will under the hood execute `cargo check`. Any warnings
applicable to your crate will be automatically fixed (if possible) and all
remaining warnings will be displayed when the check process is finished. For
example if you'd like to prepare for the 2018 edition, you can do so by
executing:

    cargo fix --edition

which behaves the same as `cargo check --all-targets`. Similarly if you'd like
to fix code for different platforms you can do:

    cargo fix --edition --target x86_64-pc-windows-gnu

or if your crate has optional features:

    cargo fix --edition --no-default-features --features foo

If you encounter any problems with `cargo fix` or otherwise have any questions
or feature requests please don't hesitate to file an issue at
https://github.com/rust-lang/cargo
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;
    let test = match args.value_of("profile") {
        Some("test") => true,
        None => false,
        Some(profile) => {
            let err = failure::format_err!(
                "unknown profile: `{}`, only `test` is \
                 currently supported",
                profile
            );
            return Err(CliError::new(err, 101));
        }
    };
    let mode = CompileMode::Check { test };

    // Unlike other commands default `cargo fix` to all targets to fix as much
    // code as we can.
    let mut opts = args.compile_options(config, mode, Some(&ws))?;

    let use_clippy = args.is_present("clippy");

    let clippy_args = args
        .value_of("clippy") // always yields None
        .map(|s| s.split(' ').map(|s| s.to_string()).collect())
        .or_else(|| Some(vec![]))
        .filter(|_| use_clippy);

    if use_clippy && !config.cli_unstable().unstable_options {
        return Err(failure::format_err!(
            "`cargo fix --clippy` is unstable, pass `-Z unstable-options` to enable it"
        )
        .into());
    }

    if let CompileFilter::Default { .. } = opts.filter {
        opts.filter = CompileFilter::Only {
            all_targets: true,
            lib: LibRule::Default,
            bins: FilterRule::All,
            examples: FilterRule::All,
            benches: FilterRule::All,
            tests: FilterRule::All,
        }
    }

    ops::fix(
        &ws,
        &mut ops::FixOptions {
            edition: args.is_present("edition"),
            prepare_for: args.value_of("prepare-for"),
            idioms: args.is_present("idioms"),
            compile_opts: opts,
            allow_dirty: args.is_present("allow-dirty"),
            allow_no_vcs: args.is_present("allow-no-vcs"),
            allow_staged: args.is_present("allow-staged"),
            broken_code: args.is_present("broken-code"),
            clippy_args,
        },
    )?;
    Ok(())
}
<commit_msg>Fix --clippy arg for fix<commit_after>use crate::command_prelude::*;

use cargo::ops::{self, CompileFilter, FilterRule, LibRule};

pub fn cli() -> App {
    subcommand("fix")
        .about("Automatically fix lint warnings reported by rustc")
        .arg(opt("quiet", "No output printed to stdout").short("q"))
        .arg_package_spec(
            "Package(s) to fix",
            "Fix all packages in the workspace",
            "Exclude packages from the fixes",
        )
        .arg_jobs()
        .arg_targets_all(
            "Fix only this package's library",
            "Fix only the specified binary",
            "Fix all binaries",
            "Fix only the specified example",
            "Fix all examples",
            "Fix only the specified test target",
            "Fix all tests",
            "Fix only the specified bench target",
            "Fix all benches",
            "Fix all targets (default)",
        )
        .arg_release("Fix artifacts in release mode, with optimizations")
        .arg(opt("profile", "Profile to build the selected target for").value_name("PROFILE"))
        .arg_features()
        .arg_target_triple("Fix for the target triple")
        .arg_target_dir()
        .arg_manifest_path()
        .arg_message_format()
        .arg(
            Arg::with_name("broken-code")
                .long("broken-code")
                .help("Fix code even if it already has compiler errors"),
        )
        .arg(
            Arg::with_name("edition")
                .long("edition")
                .help("Fix in preparation for the next edition"),
        )
        .arg(
            // This is a deprecated argument, we'll want to phase it out
            // eventually.
            Arg::with_name("prepare-for")
                .long("prepare-for")
                .help("Fix warnings in preparation of an edition upgrade")
                .takes_value(true)
                .possible_values(&["2018"])
                .conflicts_with("edition")
                .hidden(true),
        )
        .arg(
            Arg::with_name("idioms")
                .long("edition-idioms")
                .help("Fix warnings to migrate to the idioms of an edition"),
        )
        .arg(
            Arg::with_name("allow-no-vcs")
                .long("allow-no-vcs")
                .help("Fix code even if a VCS was not detected"),
        )
        .arg(
            Arg::with_name("allow-dirty")
                .long("allow-dirty")
                .help("Fix code even if the working directory is dirty"),
        )
        .arg(
            Arg::with_name("allow-staged")
                .long("allow-staged")
                .help("Fix code even if the working directory has staged changes"),
        )
        .arg(
            Arg::with_name("clippy")
                .long("clippy")
                .help("Get fix suggestions from clippy instead of rustc")
                .hidden(true)
                .multiple(true)
                .min_values(0)
                .number_of_values(1),
        )
        .after_help(
            "\
This Cargo subcommand will automatically take rustc's suggestions from
diagnostics like warnings and apply them to your source code. This is intended
to help automate tasks that rustc itself already knows how to tell you to fix!
The `cargo fix` subcommand is also being developed for the Rust 2018 edition
to provide code the ability to easily opt-in to the new edition without having
to worry about any breakage.

Executing `cargo fix` will under the hood execute `cargo check`. Any warnings
applicable to your crate will be automatically fixed (if possible) and all
remaining warnings will be displayed when the check process is finished. For
example if you'd like to prepare for the 2018 edition, you can do so by
executing:

    cargo fix --edition

which behaves the same as `cargo check --all-targets`. Similarly if you'd like
to fix code for different platforms you can do:

    cargo fix --edition --target x86_64-pc-windows-gnu

or if your crate has optional features:

    cargo fix --edition --no-default-features --features foo

If you encounter any problems with `cargo fix` or otherwise have any questions
or feature requests please don't hesitate to file an issue at
https://github.com/rust-lang/cargo
",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
    let ws = args.workspace(config)?;
    let test = match args.value_of("profile") {
        Some("test") => true,
        None => false,
        Some(profile) => {
            let err = failure::format_err!(
                "unknown profile: `{}`, only `test` is \
                 currently supported",
                profile
            );
            return Err(CliError::new(err, 101));
        }
    };
    let mode = CompileMode::Check { test };

    // Unlike other commands default `cargo fix` to all targets to fix as much
    // code as we can.
    let mut opts = args.compile_options(config, mode, Some(&ws))?;

    let use_clippy = args.is_present("clippy");

    let clippy_args = args
        .value_of("clippy")
        .map(|s| s.split(' ').map(|s| s.to_string()).collect())
        .or_else(|| Some(vec![]))
        .filter(|_| use_clippy);

    // dbg!(&clippy_args, use_clippy);

    if use_clippy && !config.cli_unstable().unstable_options {
        return Err(failure::format_err!(
            "`cargo fix --clippy` is unstable, pass `-Z unstable-options` to enable it"
        )
        .into());
    }

    if let CompileFilter::Default { .. } = opts.filter {
        opts.filter = CompileFilter::Only {
            all_targets: true,
            lib: LibRule::Default,
            bins: FilterRule::All,
            examples: FilterRule::All,
            benches: FilterRule::All,
            tests: FilterRule::All,
        }
    }

    ops::fix(
        &ws,
        &mut ops::FixOptions {
            edition: args.is_present("edition"),
            prepare_for: args.value_of("prepare-for"),
            idioms: args.is_present("idioms"),
            compile_opts: opts,
            allow_dirty: args.is_present("allow-dirty"),
            allow_no_vcs: args.is_present("allow-no-vcs"),
            allow_staged: args.is_present("allow-staged"),
            broken_code: args.is_present("broken-code"),
            clippy_args,
        },
    )?;
    Ok(())
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use specs;
use specs::{ReadStorage, WriteStorage};
use gfx_app::mouse_controls::MouseInputState;
use graphics::camera::CameraInputState;
use graphics::orientation::Orientation;

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub x_movement: f32,
  pub y_movement: f32,
  pub orientation: Orientation,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      x_movement: 0.0,
      y_movement: 0.0,
      orientation: Orientation::Still,
    }
  }
}

impl specs::Component for CharacterInputState {
  type Storage = specs::HashMapStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: mpsc::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, mpsc::Sender<CharacterControl>) {
    let (tx, rx) = mpsc::channel();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>, ReadStorage<'a, MouseInputState>, WriteStorage<'a, CameraInputState>);

  fn run(&mut self, (mut character_input, mouse_input, mut camera_input): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CharacterControl::Up => self.y_move = Some(-0.9),
        CharacterControl::Down => self.y_move = Some(0.9),
        CharacterControl::YMoveStop => self.y_move = None,
        CharacterControl::Right => self.x_move = Some(-1.0),
        CharacterControl::Left => self.x_move = Some(1.0),
        CharacterControl::XMoveStop => self.x_move = None,
      }
    }

    if let Some(x) = self.x_move {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x / 1.5;
            ci.y_movement += y / 1.5;
            camera.x_pos += x / 1.5;
            camera.y_pos -= y / 1.5;

            if x > 0.0 {
              if y > 0.0 {
                ci.orientation = Orientation::DownLeft;
              } else if y < 0.0 {
                ci.orientation = Orientation::UpLeft;
              }
            } else if x < 0.0 {
              if y > 0.0 {
                ci.orientation = Orientation::DownRight;
              } else if y < 0.0 {
                ci.orientation = Orientation::UpRight;
              }
            }
          }
        }
      }
    }
    if let Some(x) = self.x_move {
      if self.y_move == None {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x;
            camera.x_pos += x;
            if x < 0.0 {
              ci.orientation = Orientation::Right;
            } else if x > 0.0 {
              ci.orientation = Orientation::Left;
            }
          }
        }
      }
    }
    if let Some(y) = self.y_move {
      if self.x_move == None {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.y_movement += y;
            camera.y_pos -= y;
            if y < 0.0 {
              ci.orientation = Orientation::Up;
            } else if y > 0.0 {
              ci.orientation = Orientation::Down;
            }
          }
        }
      }
    }

    if self.y_move.is_none() && self.x_move.is_none() {
      for (ci, mi) in (&mut character_input, &mouse_input).join() {
        if mi.left_click_point.is_none() {
          ci.orientation = Orientation::Still;
        }
      }
    }
  }
}
<commit_msg>Refactor character control function<commit_after>use std::sync::mpsc;
use specs;
use specs::{ReadStorage, WriteStorage};
use gfx_app::mouse_controls::MouseInputState;
use graphics::camera::CameraInputState;
use graphics::orientation::Orientation;

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub x_movement: f32,
  pub y_movement: f32,
  pub orientation: Orientation,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      x_movement: 0.0,
      y_movement: 0.0,
      orientation: Orientation::Still,
    }
  }
}

impl specs::Component for CharacterInputState {
  type Storage = specs::HashMapStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: mpsc::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, mpsc::Sender<CharacterControl>) {
    let (tx, rx) = mpsc::channel();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>, ReadStorage<'a, MouseInputState>, WriteStorage<'a, CameraInputState>);

  fn run(&mut self, (mut character_input, mouse_input, mut camera_input): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CharacterControl::Up => self.y_move = Some(-0.9),
        CharacterControl::Down => self.y_move = Some(0.9),
        CharacterControl::YMoveStop => self.y_move = None,
        CharacterControl::Right => self.x_move = Some(-1.0),
        CharacterControl::Left => self.x_move = Some(1.0),
        CharacterControl::XMoveStop => self.x_move = None,
      }
    }

    if self.y_move.is_none() && self.x_move.is_none() {
      for (ci, mi) in (&mut character_input, &mouse_input).join() {
        if mi.left_click_point.is_none() {
          ci.orientation = Orientation::Still;
        }
      }
    } else if self.x_move.is_none() {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.y_movement += y;
            camera.y_pos -= y;
            ci.orientation =
              if y < 0.0 { Orientation::Up } else if y > 0.0 { Orientation::Down } else { Orientation::Still };
          }
        }
      }
    } else if let Some(x) = self.x_move {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x / 1.5;
            ci.y_movement += y / 1.5;
            camera.x_pos += x / 1.5;
            camera.y_pos -= y / 1.5;

            ci.orientation = match (x, y) {
              (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
              (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
              (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
              (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
              _ => Orientation::Still,
            };
          }
        }
      } else if self.y_move.is_none() {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() {
            ci.x_movement += x;
            camera.x_pos += x;
            ci.orientation =
              if x < 0.0 { Orientation::Right } else if x > 0.0 { Orientation::Left } else { Orientation::Still };
          }
        }
      }
    }
  }
}
<|endoftext|>