<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,
}

pub struct Engine {
  engine_impl: EngineImpl,
  animating: bool,
  angle: f32,  // in degrees.
  /// 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,
      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,
      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.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.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.angle += 360.0 / 600.0;
      if self.angle > 360.0 {
        self.angle = 0.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 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);
  let center = Point3::new(p.x as f32 + s, y, p.x 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>Extract struct Fov, move inc_angle() into it.<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 {
  angle: f32,  // in degrees.
}

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 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);
  let center = Point3::new(p.x as f32 + s, y, p.x 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)
}
<|endoftext|>


<commit_before>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

//! Boilerplatey error enums

extern crate core;
use self::core::fmt::{self,Display,Formatter};
#[cfg(not(feature="no_std"))]
use std::error::Error;

macro_rules! simple {(#[$tydoc:meta] $err:ident  {
                          $($(#[$vardoc:meta])* ::$variant:ident => $string:expr),+,
                      } ) => {
    #[$tydoc]
    #[derive(Clone,Copy, Debug, PartialEq,Eq)]
    pub enum $err {
        $($(#[$vardoc])* $variant),*
    }
    #[cfg(feature="no_std")]
    impl $err {
        #[allow(missing_docs)]
        pub fn description(&self) -> &'static str {
            match *self {$($err::$variant=>$string),*}
        }
    }
    #[cfg(not(feature="no_std"))]
    impl Error for $err {
        fn description(&self) -> &'static str {
            match *self {$($err::$variant=>$string),*}
        }
    }
    impl Display for $err {
        fn fmt(&self,  fmtr: &mut Formatter) -> fmt::Result {
            write!(fmtr, "{}", self.description())
        }
    }
}}

simple!{/// Reasons why an `u32` is not a valid UTF codepoint.
    InvalidCodepoint {
        /// It's reserved for UTF-16 surrogate pairs."
        ::Utf16Reserved => "is reserved for UTF-16 surrogate pairs",
        /// It's higher than the highest codepoint (which is 0x10ffff).
        ::TooHigh => "is higher than the highest codepoint",
    }}
use self::InvalidCodepoint::*;
impl InvalidCodepoint {
    /// Get the range of values for which this error would be given.
    pub fn error_range(self) -> (u32,u32) {match self {
        Utf16Reserved => (0xd8_00, 0xdf_ff),
        TooHigh => (0x00_10_ff_ff, 0xff_ff_ff_ff),
    }}
}

simple!{/// Reasons why one or two `u16`s are not valid UTF-16, in sinking precedence.
    InvalidUtf16Tuple {
        /// The first unit is a trailing/low surrogate, which is never valid.
        ///
        /// Note that the value of a low surrogate is actually higher than a high surrogate.
        ::FirstIsTrailingSurrogate => "the first unit is a trailing / low surrogate, which is never valid",
        /// You provided a second unit, but the first one stands on its own.
        ::SuperfluousSecond => "the second unit is superfluous",
        /// The first and only unit requires a second unit.
        ::MissingSecond => "the first unit requires a second unit",
        /// The first unit requires a second unit, but it's not a trailing/low surrogate.
        ///
        /// Note that the value of a low surrogate is actually higher than a high surrogate.
        ::InvalidSecond => "the required second unit is not a trailing / low surrogate",
    }}

simple!{/// Reasons why a slice of `u16`s doesn't start with valid UTF-16.
    InvalidUtf16Slice {
        /// The slice is empty.
        ::EmptySlice => "the slice is empty",
        /// The first unit is a low surrogate.
        ::FirstLowSurrogate => "the first unit is a low surrogate",
        /// The first and only unit requires a second unit.
        ::MissingSecond => "the first and only unit requires a second one",
        /// The first unit requires a second one, but it's not a low surrogate.
        ::SecondNotLowSurrogate => "the required second unit is not a low surrogate",
    }}

simple!{/// Reasons why `Utf8Char::from_str()` failed.
    FromStrError {
        /// `Utf8Char` cannot store more than a single codepoint.
        ::MultipleCodepoints => "has more than one codepoint",
        /// `Utf8Char` cannot be empty.
        ::Empty => "is empty",
    }}

simple!{/// Reasons why a byte is not the start of a UTF-8 codepoint.
    InvalidUtf8FirstByte {
        /// Sequences cannot be longer than 4 bytes. Is given for values >= 240.
        ::TooLongSeqence => "is greater than 239 (UTF-8 seqences cannot be longer than four bytes)",
        /// This byte belongs to a previous seqence. Is given for values between 128 and 192 (exclusive).
        ::ContinuationByte => "is a continuation of a previous sequence",
    }}
use self::InvalidUtf8FirstByte::*;

macro_rules! complex {
($err:ty
 {$($sub:ty => $to:expr,)*}
 {$($desc:pat => $string:expr),+,}
 => $use_cause:expr =>
 {$($cause:pat => $result:expr),+,} $(#[$causedoc:meta])*
) => {
    $(impl From<$sub> for $err {
          fn from(error: $sub) -> $err {
              $to(error)
          }
      })*
    #[cfg(feature="no_std")]
    impl $err {
        #[allow(missing_docs)]
        pub fn description(&self) -> &'static str {
            match *self{ $($desc => $string,)* }
        }
        /// A hack to avoid two Display impls
        fn cause(&self) -> Option<&Display> {None}
    }
    #[cfg(not(feature="no_std"))]
    impl Error for $err {
        fn description(&self) -> &'static str {
            match *self{ $($desc => $string,)* }
        }
        $(#[$causedoc])*
        fn cause(&self) -> Option<&Error> {
            match *self{ $($cause => $result,)* }
        }
    }
    impl Display for $err {
        fn fmt(&self,  fmtr: &mut Formatter) -> fmt::Result {
            match (self.cause(), $use_cause) {
                (Some(d),true) => write!(fmtr, "{}: {}", self.description(), d),
                        _      => write!(fmtr, "{}", self.description()),
            }
        }
    }
}}

/// Reasons why a byte sequence is not valid UTF-8, excluding invalid codepoint.
/// In sinking precedence.
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum InvalidUtf8 {
    /// Something is wrong with the first byte.
    FirstByte(InvalidUtf8FirstByte),
    /// Thee byte at index 1...3 should be a continuation byte,
    /// but dosesn't fit the pattern 0b10xx_xxxx.
    NotAContinuationByte(usize),
    /// There are too many leading zeros: it could be a byte shorter.
    OverLong,
}
use self::InvalidUtf8::*;
complex!{InvalidUtf8 {
        InvalidUtf8FirstByte => FirstByte,
    } {
        FirstByte(TooLongSeqence) => "the first byte is greater than 239 (UTF-8 seqences cannot be longer than four bytes)",
        FirstByte(ContinuationByte) => "the first byte is a continuation of a previous sequence",
        OverLong => "the seqence contains too many zeros and could be shorter",
        NotAContinuationByte(_) => "the sequence is too short",
    } => false => {
        FirstByte(ref cause) => Some(cause),
        _ => None,
    }/// Returns `Some` if the error is a `InvalidUtf8FirstByte`.
}

/// Reasons why a byte array is not valid UTF-8, in sinking precedence.
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum InvalidUtf8Array {
    /// Not a valid UTF-8 sequence.
    Utf8(InvalidUtf8),
    /// Not a valid unicode codepoint.
    Codepoint(InvalidCodepoint),
}
complex!{InvalidUtf8Array {
        InvalidUtf8 => InvalidUtf8Array::Utf8,
        InvalidCodepoint => InvalidUtf8Array::Codepoint,
    } {
        InvalidUtf8Array::Utf8(_) => "the seqence is invalid UTF-8",
        InvalidUtf8Array::Codepoint(_) => "the encoded codepoint is invalid",
    } => true => {
        InvalidUtf8Array::Utf8(ref u) => Some(u),
        InvalidUtf8Array::Codepoint(ref c) => Some(c),
    }/// Always returns `Some`.
}

/// Reasons why a byte slice is not valid UTF-8, in sinking precedence.
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum InvalidUtf8Slice {
    /// Something is certainly wrong with the first byte.
    Utf8(InvalidUtf8),
    /// The encoded codepoint is invalid:
    Codepoint(InvalidCodepoint),
    /// The slice is too short; n bytes was required.
    TooShort(usize),
}
complex!{InvalidUtf8Slice {
        InvalidUtf8 => InvalidUtf8Slice::Utf8,
        InvalidCodepoint => InvalidUtf8Slice::Codepoint,
    } {
        InvalidUtf8Slice::Utf8(_) => "the seqence is invalid UTF-8",
        InvalidUtf8Slice::Codepoint(_) => "the encoded codepoint is invalid",
        InvalidUtf8Slice::TooShort(0) => "the slice is empty",
        InvalidUtf8Slice::TooShort(_) => "the slice is shorter than the seqence",
    } => true => {
        InvalidUtf8Slice::Utf8(ref u) => Some(u),
        InvalidUtf8Slice::Codepoint(ref c) => Some(c),
        InvalidUtf8Slice::TooShort(_) => None,
    }
}
<commit_msg>Explain why overlong UTF-8 is an error<commit_after>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

//! Boilerplatey error enums

extern crate core;
use self::core::fmt::{self,Display,Formatter};
#[cfg(not(feature="no_std"))]
use std::error::Error;

macro_rules! simple {(#[$tydoc:meta] $err:ident  {
                          $($(#[$vardoc:meta])* ::$variant:ident => $string:expr),+,
                      } ) => {
    #[$tydoc]
    #[derive(Clone,Copy, Debug, PartialEq,Eq)]
    pub enum $err {
        $($(#[$vardoc])* $variant),*
    }
    #[cfg(feature="no_std")]
    impl $err {
        #[allow(missing_docs)]
        pub fn description(&self) -> &'static str {
            match *self {$($err::$variant=>$string),*}
        }
    }
    #[cfg(not(feature="no_std"))]
    impl Error for $err {
        fn description(&self) -> &'static str {
            match *self {$($err::$variant=>$string),*}
        }
    }
    impl Display for $err {
        fn fmt(&self,  fmtr: &mut Formatter) -> fmt::Result {
            write!(fmtr, "{}", self.description())
        }
    }
}}

simple!{/// Reasons why an `u32` is not a valid UTF codepoint.
    InvalidCodepoint {
        /// It's reserved for UTF-16 surrogate pairs."
        ::Utf16Reserved => "is reserved for UTF-16 surrogate pairs",
        /// It's higher than the highest codepoint (which is 0x10ffff).
        ::TooHigh => "is higher than the highest codepoint",
    }}
use self::InvalidCodepoint::*;
impl InvalidCodepoint {
    /// Get the range of values for which this error would be given.
    pub fn error_range(self) -> (u32,u32) {match self {
        Utf16Reserved => (0xd8_00, 0xdf_ff),
        TooHigh => (0x00_10_ff_ff, 0xff_ff_ff_ff),
    }}
}

simple!{/// Reasons why one or two `u16`s are not valid UTF-16, in sinking precedence.
    InvalidUtf16Tuple {
        /// The first unit is a trailing/low surrogate, which is never valid.
        ///
        /// Note that the value of a low surrogate is actually higher than a high surrogate.
        ::FirstIsTrailingSurrogate => "the first unit is a trailing / low surrogate, which is never valid",
        /// You provided a second unit, but the first one stands on its own.
        ::SuperfluousSecond => "the second unit is superfluous",
        /// The first and only unit requires a second unit.
        ::MissingSecond => "the first unit requires a second unit",
        /// The first unit requires a second unit, but it's not a trailing/low surrogate.
        ///
        /// Note that the value of a low surrogate is actually higher than a high surrogate.
        ::InvalidSecond => "the required second unit is not a trailing / low surrogate",
    }}

simple!{/// Reasons why a slice of `u16`s doesn't start with valid UTF-16.
    InvalidUtf16Slice {
        /// The slice is empty.
        ::EmptySlice => "the slice is empty",
        /// The first unit is a low surrogate.
        ::FirstLowSurrogate => "the first unit is a low surrogate",
        /// The first and only unit requires a second unit.
        ::MissingSecond => "the first and only unit requires a second one",
        /// The first unit requires a second one, but it's not a low surrogate.
        ::SecondNotLowSurrogate => "the required second unit is not a low surrogate",
    }}

simple!{/// Reasons why `Utf8Char::from_str()` failed.
    FromStrError {
        /// `Utf8Char` cannot store more than a single codepoint.
        ::MultipleCodepoints => "has more than one codepoint",
        /// `Utf8Char` cannot be empty.
        ::Empty => "is empty",
    }}

simple!{/// Reasons why a byte is not the start of a UTF-8 codepoint.
    InvalidUtf8FirstByte {
        /// Sequences cannot be longer than 4 bytes. Is given for values >= 240.
        ::TooLongSeqence => "is greater than 239 (UTF-8 seqences cannot be longer than four bytes)",
        /// This byte belongs to a previous seqence. Is given for values between 128 and 192 (exclusive).
        ::ContinuationByte => "is a continuation of a previous sequence",
    }}
use self::InvalidUtf8FirstByte::*;

macro_rules! complex {
($err:ty
 {$($sub:ty => $to:expr,)*}
 {$($desc:pat => $string:expr),+,}
 => $use_cause:expr =>
 {$($cause:pat => $result:expr),+,} $(#[$causedoc:meta])*
) => {
    $(impl From<$sub> for $err {
          fn from(error: $sub) -> $err {
              $to(error)
          }
      })*
    #[cfg(feature="no_std")]
    impl $err {
        #[allow(missing_docs)]
        pub fn description(&self) -> &'static str {
            match *self{ $($desc => $string,)* }
        }
        /// A hack to avoid two Display impls
        fn cause(&self) -> Option<&Display> {None}
    }
    #[cfg(not(feature="no_std"))]
    impl Error for $err {
        fn description(&self) -> &'static str {
            match *self{ $($desc => $string,)* }
        }
        $(#[$causedoc])*
        fn cause(&self) -> Option<&Error> {
            match *self{ $($cause => $result,)* }
        }
    }
    impl Display for $err {
        fn fmt(&self,  fmtr: &mut Formatter) -> fmt::Result {
            match (self.cause(), $use_cause) {
                (Some(d),true) => write!(fmtr, "{}: {}", self.description(), d),
                        _      => write!(fmtr, "{}", self.description()),
            }
        }
    }
}}

/// Reasons why a byte sequence is not valid UTF-8, excluding invalid codepoint.
/// In sinking precedence.
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum InvalidUtf8 {
    /// Something is wrong with the first byte.
    FirstByte(InvalidUtf8FirstByte),
    /// Thee byte at index 1...3 should be a continuation byte,
    /// but dosesn't fit the pattern 0b10xx_xxxx.
    NotAContinuationByte(usize),
    /// There are too many leading zeros: it could be a byte shorter.
    ///
    /// [Decoding this could allow someone to input otherwise prohibited
    /// characters and sequences, such as "../"](https://tools.ietf.org/html/rfc3629#section-10).
    OverLong,
}
use self::InvalidUtf8::*;
complex!{InvalidUtf8 {
        InvalidUtf8FirstByte => FirstByte,
    } {
        FirstByte(TooLongSeqence) => "the first byte is greater than 239 (UTF-8 seqences cannot be longer than four bytes)",
        FirstByte(ContinuationByte) => "the first byte is a continuation of a previous sequence",
        OverLong => "the seqence contains too many zeros and could be shorter",
        NotAContinuationByte(_) => "the sequence is too short",
    } => false => {
        FirstByte(ref cause) => Some(cause),
        _ => None,
    }/// Returns `Some` if the error is a `InvalidUtf8FirstByte`.
}

/// Reasons why a byte array is not valid UTF-8, in sinking precedence.
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum InvalidUtf8Array {
    /// Not a valid UTF-8 sequence.
    Utf8(InvalidUtf8),
    /// Not a valid unicode codepoint.
    Codepoint(InvalidCodepoint),
}
complex!{InvalidUtf8Array {
        InvalidUtf8 => InvalidUtf8Array::Utf8,
        InvalidCodepoint => InvalidUtf8Array::Codepoint,
    } {
        InvalidUtf8Array::Utf8(_) => "the seqence is invalid UTF-8",
        InvalidUtf8Array::Codepoint(_) => "the encoded codepoint is invalid",
    } => true => {
        InvalidUtf8Array::Utf8(ref u) => Some(u),
        InvalidUtf8Array::Codepoint(ref c) => Some(c),
    }/// Always returns `Some`.
}

/// Reasons why a byte slice is not valid UTF-8, in sinking precedence.
#[derive(Clone,Copy, Debug, PartialEq,Eq)]
pub enum InvalidUtf8Slice {
    /// Something is certainly wrong with the first byte.
    Utf8(InvalidUtf8),
    /// The encoded codepoint is invalid:
    Codepoint(InvalidCodepoint),
    /// The slice is too short; n bytes was required.
    TooShort(usize),
}
complex!{InvalidUtf8Slice {
        InvalidUtf8 => InvalidUtf8Slice::Utf8,
        InvalidCodepoint => InvalidUtf8Slice::Codepoint,
    } {
        InvalidUtf8Slice::Utf8(_) => "the seqence is invalid UTF-8",
        InvalidUtf8Slice::Codepoint(_) => "the encoded codepoint is invalid",
        InvalidUtf8Slice::TooShort(0) => "the slice is empty",
        InvalidUtf8Slice::TooShort(_) => "the slice is shorter than the seqence",
    } => true => {
        InvalidUtf8Slice::Utf8(ref u) => Some(u),
        InvalidUtf8Slice::Codepoint(ref c) => Some(c),
        InvalidUtf8Slice::TooShort(_) => None,
    }
}
<|endoftext|>


<commit_before>use std::io::{Writer, IoResult};
use super::Rgb;
use geom::{V2};
use canvas::{Context, FONT_W, FONT_H};

/// Writing text to a graphical context.
pub trait Fonter<'a, W: Writer> {
    fn text_writer(&'a mut self, origin: V2<int>, z: f32, color: Rgb) -> W;
}

impl<'a> Fonter<'a, CanvasWriter<'a>> for Context {
    fn text_writer(&'a mut self, origin: V2<int>, z: f32, color: Rgb) -> CanvasWriter<'a> {
        CanvasWriter {
            context: self,
            origin: origin,
            cursor_pos: origin,
            color: color,
            z: z,
            border: None,
        }
    }
}

pub struct CanvasWriter<'a> {
    context: &'a mut Context,
    origin: V2<int>,
    cursor_pos: V2<int>,
    /// Text color
    pub color: Rgb,
    /// Z drawing depth
    pub z: f32,
    /// Border color (if any)
    pub border: Option<Rgb>,
}

impl<'a> CanvasWriter<'a> {
    pub fn set_border(mut self, c: Rgb) -> CanvasWriter<'a> {
        self.border = Some(c);
        self
    }

    fn draw_char(&mut self, c: char) {
        static BORDER: [V2<int>, ..8] =
            [V2(-1, -1), V2( 0, -1), V2( 1, -1),
             V2(-1,  0),             V2( 1,  0),
             V2(-1,  1), V2( 0,  1), V2( 1,  1)];
        if let Some(img) = self.context.font_image(c) {
            if let Some(b) = self.border {
                for &d in BORDER.iter() {
                    self.context.draw_image(self.cursor_pos + d, self.z, img, &b);
                }
            }
            self.context.draw_image(self.cursor_pos, self.z, img, &self.color);
        }
    }
}

impl<'a> Writer for CanvasWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        // TODO: Support multibyte stuff.
        for &b in buf.iter() {
            let c = b as char;
            if c == '\n' {
                self.cursor_pos = V2(self.origin.0, self.cursor_pos.1 + FONT_H as int);
            } else {
                self.draw_char(c);
                self.cursor_pos.0 += FONT_W as int;
            }
        }
        Ok(())
    }
}
<commit_msg>Text border doesn't clobber main text<commit_after>use std::io::{Writer, IoResult};
use super::Rgb;
use geom::{V2};
use canvas::{Context, FONT_W, FONT_H};

/// Writing text to a graphical context.
pub trait Fonter<'a, W: Writer> {
    fn text_writer(&'a mut self, origin: V2<int>, z: f32, color: Rgb) -> W;
}

impl<'a> Fonter<'a, CanvasWriter<'a>> for Context {
    fn text_writer(&'a mut self, origin: V2<int>, z: f32, color: Rgb) -> CanvasWriter<'a> {
        CanvasWriter {
            context: self,
            origin: origin,
            cursor_pos: origin,
            color: color,
            z: z,
            border: None,
        }
    }
}

pub struct CanvasWriter<'a> {
    context: &'a mut Context,
    origin: V2<int>,
    cursor_pos: V2<int>,
    /// Text color
    pub color: Rgb,
    /// Z drawing depth
    pub z: f32,
    /// Border color (if any)
    pub border: Option<Rgb>,
}

impl<'a> CanvasWriter<'a> {
    pub fn set_border(mut self, c: Rgb) -> CanvasWriter<'a> {
        self.border = Some(c);
        self
    }

    fn draw_char(&mut self, c: char) {
        static BORDER: [V2<int>, ..8] =
            [V2(-1, -1), V2( 0, -1), V2( 1, -1),
             V2(-1,  0),             V2( 1,  0),
             V2(-1,  1), V2( 0,  1), V2( 1,  1)];
        if let Some(img) = self.context.font_image(c) {
            if let Some(b) = self.border {
                // Put the border a tiny bit further in the z-buffer so it
                // won't clobber the text on the same layer.
                let border_z = self.z + 0.00001;
                for &d in BORDER.iter() {
                    self.context.draw_image(self.cursor_pos + d, border_z, img, &b);
                }
            }
            self.context.draw_image(self.cursor_pos, self.z, img, &self.color);
        }
    }
}

impl<'a> Writer for CanvasWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        // TODO: Support multibyte stuff.
        for &b in buf.iter() {
            let c = b as char;
            if c == '\n' {
                self.cursor_pos = V2(self.origin.0, self.cursor_pos.1 + FONT_H as int);
            } else {
                self.draw_char(c);
                self.cursor_pos.0 += FONT_W as int;
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

use {serde, tokio_core};
use bincode::{SizeLimit, serde as bincode};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::io::{self, Cursor};
use std::marker::PhantomData;
use std::mem;
use tokio_core::io::{EasyBuf, Framed, Io};
use tokio_proto::streaming::multiplex::{self, RequestId};
use tokio_proto::multiplex::{ClientProto, ServerProto};
use util::{Debugger, Never};

/// The type of message sent and received by the transport.
pub type Frame<T> = multiplex::Frame<T, Never, io::Error>;

// `T` is the type that `Codec` parses.
pub struct Codec<Req, Resp> {
    state: CodecState,
    _phantom_data: PhantomData<(Req, Resp)>,
}

enum CodecState {
    Id,
    Len { id: u64 },
    Payload { id: u64, len: u64 },
}

impl<Req, Resp> Codec<Req, Resp> {
    fn new() -> Self {
        Codec {
            state: CodecState::Id,
            _phantom_data: PhantomData,
        }
    }
}

impl<Req, Resp> tokio_core::io::Codec for Codec<Req, Resp>
    where Req: serde::Deserialize,
          Resp: serde::Serialize,
{
    type Out = (RequestId, Resp);
    type In = (RequestId, Result<Req, bincode::DeserializeError>);

    fn encode(&mut self, (id, message): Self::Out, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.write_u64::<BigEndian>(id).unwrap();
        trace!("Encoded request id = {} as {:?}", id, buf);
        buf.write_u64::<BigEndian>(bincode::serialized_size(&message)).unwrap();
        bincode::serialize_into(buf,
                                &message,
                                SizeLimit::Infinite)
                 // TODO(tikue): handle err
                 .expect("In bincode::serialize_into");
        trace!("Encoded buffer: {:?}", buf);
        Ok(())
    }

    fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<Self::In>, io::Error> {
        use self::CodecState::*;
        trace!("Codec::decode: {:?}", buf.as_slice());

        loop {
            match self.state {
                Id if buf.len() < mem::size_of::<u64>() => {
                    trace!("--> Buf len is {}; waiting for 8 to parse id.", buf.len());
                    return Ok(None)
                }
                Id => {
                    let mut id_buf = buf.drain_to(mem::size_of::<u64>());
                    let id = Cursor::new(&mut id_buf).read_u64::<BigEndian>()?;
                    trace!("--> Parsed id = {} from {:?}", id, id_buf.as_slice());
                    self.state = Len { id: id };
                }
                Len { .. } if buf.len() < mem::size_of::<u64>() => {
                    trace!("--> Buf len is {}; waiting for 8 to parse packet length.", buf.len());
                    return Ok(None)
                }
                Len { id } => {
                    let len_buf = buf.drain_to(mem::size_of::<u64>());
                    let len = Cursor::new(len_buf).read_u64::<BigEndian>()?;
                    trace!("--> Parsed payload length = {}, remaining buffer length = {}",
                           len, buf.len());
                    self.state = Payload {
                        id: id,
                        len: len,
                    };
                }
                Payload { len, .. } if buf.len() < len as usize => {
                    trace!("--> Buf len is {}; waiting for {} to parse payload.", buf.len(), len);
                    return Ok(None)
                }
                Payload { id, len } => {
                    let payload = buf.drain_to(len as usize);
                    let result = bincode::deserialize_from(&mut Cursor::new(payload),
                                                           SizeLimit::Infinite);
                    // Reset the state machine because, either way, we're done processing this
                    // message.
                    self.state = Id;

                    trace!("--> Parsed message: {:?}", Debugger(&result));
                    return Ok(Some((id, result)));
                }
            }
        }
    }
}

/// Implements the `multiplex::ServerProto` trait.
pub struct Proto<Req, Resp>(PhantomData<(Req, Resp)>);

impl<Req, Resp> Proto<Req, Resp> {
    /// Returns a new `Proto`.
    pub fn new() -> Self {
        Proto(PhantomData)
    }
}

impl<T, Req, Resp> ServerProto<T> for Proto<Req, Resp>
    where T: Io + 'static,
          Req: serde::Deserialize + 'static,
          Resp: serde::Serialize + 'static,
{
    type Response = Resp;
    type Request = Result<Req, bincode::DeserializeError>;
    type Error = io::Error;
    type Transport = Framed<T, Codec<Req, Resp>>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(Codec::new()))
    }
}

impl<T, Req, Resp> ClientProto<T> for Proto<Req, Resp>
    where T: Io + 'static,
          Req: serde::Serialize + 'static,
          Resp: serde::Deserialize + 'static,
{
    type Response = Result<Resp, bincode::DeserializeError>;
    type Request = Req;
    type Error = io::Error;
    type Transport = Framed<T, Codec<Resp, Req>>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(Codec::new()))
    }
}

#[test]
fn serialize() {
    use tokio_core::io::Codec as TokioCodec;

    const MSG: (u64, (char, char, char)) = (4, ('a', 'b', 'c'));
    let mut buf = EasyBuf::new();
    let mut vec = Vec::new();

    // Serialize twice to check for idempotence.
    for _ in 0..2 {
        let mut codec: Codec<(char, char, char), (char, char, char)> = Codec::new();
        codec.encode(MSG, &mut vec).unwrap();
        buf.get_mut().append(&mut vec);
        let actual: Result<Option<(u64, Result<(char, char, char), bincode::DeserializeError>)>, io::Error> =
            codec.decode(&mut buf);

        match actual {
            Ok(Some((id, ref v))) if id == MSG.0 && *v.as_ref().unwrap() == MSG.1 => {}
            bad => panic!("Expected {:?}, but got {:?}", Some(MSG), bad),
        }

        assert!(buf.get_mut().is_empty(),
                "Expected empty buf but got {:?}",
                *buf.get_mut());
    }
}
<commit_msg>Fix stale comment<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the MIT License, <LICENSE or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

use {serde, tokio_core};
use bincode::{SizeLimit, serde as bincode};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::io::{self, Cursor};
use std::marker::PhantomData;
use std::mem;
use tokio_core::io::{EasyBuf, Framed, Io};
use tokio_proto::streaming::multiplex::{self, RequestId};
use tokio_proto::multiplex::{ClientProto, ServerProto};
use util::{Debugger, Never};

/// The type of message sent and received by the transport.
pub type Frame<T> = multiplex::Frame<T, Never, io::Error>;

// `Req` is the type that `Codec` parses. `Resp` is the type it serializes.
pub struct Codec<Req, Resp> {
    state: CodecState,
    _phantom_data: PhantomData<(Req, Resp)>,
}

enum CodecState {
    Id,
    Len { id: u64 },
    Payload { id: u64, len: u64 },
}

impl<Req, Resp> Codec<Req, Resp> {
    fn new() -> Self {
        Codec {
            state: CodecState::Id,
            _phantom_data: PhantomData,
        }
    }
}

impl<Req, Resp> tokio_core::io::Codec for Codec<Req, Resp>
    where Req: serde::Deserialize,
          Resp: serde::Serialize,
{
    type Out = (RequestId, Resp);
    type In = (RequestId, Result<Req, bincode::DeserializeError>);

    fn encode(&mut self, (id, message): Self::Out, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.write_u64::<BigEndian>(id).unwrap();
        trace!("Encoded request id = {} as {:?}", id, buf);
        buf.write_u64::<BigEndian>(bincode::serialized_size(&message)).unwrap();
        bincode::serialize_into(buf,
                                &message,
                                SizeLimit::Infinite)
                 // TODO(tikue): handle err
                 .expect("In bincode::serialize_into");
        trace!("Encoded buffer: {:?}", buf);
        Ok(())
    }

    fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<Self::In>, io::Error> {
        use self::CodecState::*;
        trace!("Codec::decode: {:?}", buf.as_slice());

        loop {
            match self.state {
                Id if buf.len() < mem::size_of::<u64>() => {
                    trace!("--> Buf len is {}; waiting for 8 to parse id.", buf.len());
                    return Ok(None)
                }
                Id => {
                    let mut id_buf = buf.drain_to(mem::size_of::<u64>());
                    let id = Cursor::new(&mut id_buf).read_u64::<BigEndian>()?;
                    trace!("--> Parsed id = {} from {:?}", id, id_buf.as_slice());
                    self.state = Len { id: id };
                }
                Len { .. } if buf.len() < mem::size_of::<u64>() => {
                    trace!("--> Buf len is {}; waiting for 8 to parse packet length.", buf.len());
                    return Ok(None)
                }
                Len { id } => {
                    let len_buf = buf.drain_to(mem::size_of::<u64>());
                    let len = Cursor::new(len_buf).read_u64::<BigEndian>()?;
                    trace!("--> Parsed payload length = {}, remaining buffer length = {}",
                           len, buf.len());
                    self.state = Payload {
                        id: id,
                        len: len,
                    };
                }
                Payload { len, .. } if buf.len() < len as usize => {
                    trace!("--> Buf len is {}; waiting for {} to parse payload.", buf.len(), len);
                    return Ok(None)
                }
                Payload { id, len } => {
                    let payload = buf.drain_to(len as usize);
                    let result = bincode::deserialize_from(&mut Cursor::new(payload),
                                                           SizeLimit::Infinite);
                    // Reset the state machine because, either way, we're done processing this
                    // message.
                    self.state = Id;

                    trace!("--> Parsed message: {:?}", Debugger(&result));
                    return Ok(Some((id, result)));
                }
            }
        }
    }
}

/// Implements the `multiplex::ServerProto` trait.
pub struct Proto<Req, Resp>(PhantomData<(Req, Resp)>);

impl<Req, Resp> Proto<Req, Resp> {
    /// Returns a new `Proto`.
    pub fn new() -> Self {
        Proto(PhantomData)
    }
}

impl<T, Req, Resp> ServerProto<T> for Proto<Req, Resp>
    where T: Io + 'static,
          Req: serde::Deserialize + 'static,
          Resp: serde::Serialize + 'static,
{
    type Response = Resp;
    type Request = Result<Req, bincode::DeserializeError>;
    type Error = io::Error;
    type Transport = Framed<T, Codec<Req, Resp>>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(Codec::new()))
    }
}

impl<T, Req, Resp> ClientProto<T> for Proto<Req, Resp>
    where T: Io + 'static,
          Req: serde::Serialize + 'static,
          Resp: serde::Deserialize + 'static,
{
    type Response = Result<Resp, bincode::DeserializeError>;
    type Request = Req;
    type Error = io::Error;
    type Transport = Framed<T, Codec<Resp, Req>>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(Codec::new()))
    }
}

#[test]
fn serialize() {
    use tokio_core::io::Codec as TokioCodec;

    const MSG: (u64, (char, char, char)) = (4, ('a', 'b', 'c'));
    let mut buf = EasyBuf::new();
    let mut vec = Vec::new();

    // Serialize twice to check for idempotence.
    for _ in 0..2 {
        let mut codec: Codec<(char, char, char), (char, char, char)> = Codec::new();
        codec.encode(MSG, &mut vec).unwrap();
        buf.get_mut().append(&mut vec);
        let actual: Result<Option<(u64, Result<(char, char, char), bincode::DeserializeError>)>, io::Error> =
            codec.decode(&mut buf);

        match actual {
            Ok(Some((id, ref v))) if id == MSG.0 && *v.as_ref().unwrap() == MSG.1 => {}
            bad => panic!("Expected {:?}, but got {:?}", Some(MSG), bad),
        }

        assert!(buf.get_mut().is_empty(),
                "Expected empty buf but got {:?}",
                *buf.get_mut());
    }
}
<|endoftext|>


<commit_before>
use std::io::Read;  // Trait providing read_to_string()

use std::env;

use hyper;
use serde;
use serde_json;

use Version;
use Projects;
use Groups;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

#[derive(Debug)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                },
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {page: 1, per_page: 20},
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:443/api/v3/projects?private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("projects"), expected_url);
    /// ```
    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}&page={}&per_page={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token,
                                self.pagination.page,
                                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, command: &str) -> Result<T, serde_json::Error>
            where T: serde::Deserialize {

        let url = self.build_url(command);
        let mut res: hyper::client::Response =
                        self.client
                        .get(&url)
                        .header(hyper::header::Connection::close())
                        .send()
                        .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        serde_json::from_str(&body.as_str())
    }

    pub fn version(&self) -> Result<Version, serde_json::Error> {
        self.get("version")
    }

    pub fn groups(&self) -> Result<Groups, serde_json::Error> {
        self.get("groups")
    }

    pub fn projects(&self) -> Result<Projects, serde_json::Error> {
        self.get("projects")
    }
}

/*
#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
    }
}
*/
<commit_msg>Cleanup<commit_after>
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use Version;
use Projects;
use Groups;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

#[derive(Debug)]
pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                },
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {page: 1, per_page: 20},
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:443/api/v3/projects?private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("projects"), expected_url);
    /// ```
    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}&page={}&per_page={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token,
                                self.pagination.page,
                                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, command: &str) -> Result<T, serde_json::Error>
            where T: serde::Deserialize {

        let url = self.build_url(command);
        let mut res: hyper::client::Response =
                        self.client
                        .get(&url)
                        .header(hyper::header::Connection::close())
                        .send()
                        .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        serde_json::from_str(&body.as_str())
    }

    pub fn version(&self) -> Result<Version, serde_json::Error> {
        self.get("version")
    }

    pub fn groups(&self) -> Result<Groups, serde_json::Error> {
        self.get("groups")
    }

    pub fn projects(&self) -> Result<Projects, serde_json::Error> {
        self.get("projects")
    }
}

/*
#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
    }
}
*/
<|endoftext|>


<commit_before>use std::default::Default;
use std::hash::Hasher;
use std::collections::hash_state::HashState;
use rand::{self,Rng};
use murmurhash64::murmur_hash64a;

/// MurmurHash2 can also be used as the hash algorithm in a HashMap
/// (or similar). For this it implements the std::hash::Hasher trait.
///
/// # Basic Example
///
/// ```rust
/// # #![feature(std_misc)]
/// # use std::collections::HashMap;
/// # use murmurhash64::{MurmurHasher,MurmurState};
/// let s = MurmurState::new();
/// let mut hashmap : HashMap<&'static str, usize, MurmurState> = HashMap::with_hash_state(s);
/// hashmap.insert("abc", 123);
/// hashmap.insert("def", 456);
/// assert_eq!(Some(&123), hashmap.get("abc"));
/// assert_eq!(Some(&456), hashmap.get("def"));
/// ```

pub struct MurmurHasher {
    state: u64
}

impl MurmurHasher {
    pub fn new() -> MurmurHasher {
        MurmurHasher { state: 0 }
    }

    pub fn with_seed(seed: u64) -> MurmurHasher {
        MurmurHasher { state: seed }
    }
}

impl Default for MurmurHasher {
    fn default() -> MurmurHasher {
        MurmurHasher::new()
    }
}

impl Hasher for MurmurHasher {
    fn finish(&self) -> u64 {
        self.state
    }

    fn write(&mut self, buf: &[u8]) {
        self.state = murmur_hash64a(buf, self.state)
    }
}

pub struct MurmurState(u64);

impl MurmurState {
    pub fn new() -> MurmurState {
        MurmurState(0)
    }
}

impl Default for MurmurState {
    fn default() -> MurmurState { MurmurState::new() }
}

impl HashState for MurmurState {
    type Hasher = MurmurHasher;
    fn hasher(&self) -> MurmurHasher {
        MurmurHasher::with_seed(self.0)
    }
}

pub struct RandomMurmurState(u64);

impl RandomMurmurState {
    fn new() -> RandomMurmurState {
        RandomMurmurState(rand::thread_rng().gen())
    }
}

impl Default for RandomMurmurState {
    fn default() -> RandomMurmurState { RandomMurmurState::new() }
}

impl HashState for RandomMurmurState {
    type Hasher = MurmurHasher;
    fn hasher(&self) -> MurmurHasher {
        MurmurHasher::with_seed(self.0)
    }
}

#[cfg(test)]
mod test {
    use super::{MurmurState,MurmurHasher,RandomMurmurState};
    use std::collections::HashMap;

    #[test]
    fn hashmap_str() {
        let s = MurmurState::new();
        let mut hashmap : HashMap<&'static str, isize, MurmurState> = HashMap::with_hash_state(s);
        hashmap.insert("abc", 123);
        hashmap.insert("def", 456);
        assert_eq!(Some(&123), hashmap.get("abc"));
        assert_eq!(Some(&456), hashmap.get("def"));
    }

    #[test]
    fn hashmap_uint() {
        let s = MurmurState::new();
        let mut hashmap : HashMap<usize, &'static str, MurmurState> = HashMap::with_hash_state(s);
        hashmap.insert(123, "abc");
        hashmap.insert(456, "def");
        assert_eq!(Some(&"abc"), hashmap.get(&123));
        assert_eq!(Some(&"def"), hashmap.get(&456));
    }

    #[test]
    fn hashmap_default() {
        use std::collections::hash_state::DefaultState;

        let mut hash: HashMap<_, _, DefaultState<MurmurHasher>> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));

        let mut hash: HashMap<_, _, RandomMurmurState> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));
    }
}

<commit_msg>Document RandomMurmurState in example<commit_after>use std::default::Default;
use std::hash::Hasher;
use std::collections::hash_state::HashState;
use rand::{self,Rng};
use murmurhash64::murmur_hash64a;

/// MurmurHash2 can also be used as the hash algorithm in a HashMap
/// (or similar). For this it implements the std::hash::Hasher trait.
///
/// # Basic Example
///
/// ```rust
/// # #![feature(std_misc)]
/// # use std::collections::HashMap;
/// # use std::default::Default;
/// # use murmurhash64::{MurmurHasher,RandomMurmurState};
/// # use std::collections::hash_state::DefaultState;
/// let mut hashmap : HashMap<_, _, DefaultState<MurmurHasher>> = Default::default();
/// hashmap.insert("abc", 123);
/// hashmap.insert("def", 456);
/// assert_eq!(Some(&123), hashmap.get("abc"));
/// assert_eq!(Some(&456), hashmap.get("def"));
///
/// let mut hashmap : HashMap<_, _, RandomMurmurState> = Default::default();
/// hashmap.insert("abc", 123);
/// hashmap.insert("def", 456);
/// assert_eq!(Some(&123), hashmap.get("abc"));
/// assert_eq!(Some(&456), hashmap.get("def"));
/// ```

pub struct MurmurHasher {
    state: u64
}

impl MurmurHasher {
    pub fn new() -> MurmurHasher {
        MurmurHasher { state: 0 }
    }

    pub fn with_seed(seed: u64) -> MurmurHasher {
        MurmurHasher { state: seed }
    }
}

impl Default for MurmurHasher {
    fn default() -> MurmurHasher {
        MurmurHasher::new()
    }
}

impl Hasher for MurmurHasher {
    fn finish(&self) -> u64 {
        self.state
    }

    fn write(&mut self, buf: &[u8]) {
        self.state = murmur_hash64a(buf, self.state)
    }
}

pub struct MurmurState(u64);

impl MurmurState {
    pub fn new() -> MurmurState {
        MurmurState(0)
    }
}

impl Default for MurmurState {
    fn default() -> MurmurState { MurmurState::new() }
}

impl HashState for MurmurState {
    type Hasher = MurmurHasher;
    fn hasher(&self) -> MurmurHasher {
        MurmurHasher::with_seed(self.0)
    }
}

pub struct RandomMurmurState(u64);

impl RandomMurmurState {
    fn new() -> RandomMurmurState {
        RandomMurmurState(rand::thread_rng().gen())
    }
}

impl Default for RandomMurmurState {
    fn default() -> RandomMurmurState { RandomMurmurState::new() }
}

impl HashState for RandomMurmurState {
    type Hasher = MurmurHasher;
    fn hasher(&self) -> MurmurHasher {
        MurmurHasher::with_seed(self.0)
    }
}

#[cfg(test)]
mod test {
    use super::{MurmurState,MurmurHasher,RandomMurmurState};
    use std::collections::HashMap;

    #[test]
    fn hashmap_str() {
        let s = MurmurState::new();
        let mut hashmap : HashMap<&'static str, isize, MurmurState> = HashMap::with_hash_state(s);
        hashmap.insert("abc", 123);
        hashmap.insert("def", 456);
        assert_eq!(Some(&123), hashmap.get("abc"));
        assert_eq!(Some(&456), hashmap.get("def"));
    }

    #[test]
    fn hashmap_uint() {
        let s = MurmurState::new();
        let mut hashmap : HashMap<usize, &'static str, MurmurState> = HashMap::with_hash_state(s);
        hashmap.insert(123, "abc");
        hashmap.insert(456, "def");
        assert_eq!(Some(&"abc"), hashmap.get(&123));
        assert_eq!(Some(&"def"), hashmap.get(&456));
    }

    #[test]
    fn hashmap_default() {
        use std::collections::hash_state::DefaultState;

        let mut hash: HashMap<_, _, DefaultState<MurmurHasher>> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));

        let mut hash: HashMap<_, _, RandomMurmurState> = Default::default();
        hash.insert(42, "the answer");
        assert_eq!(hash.get(&42), Some(&"the answer"));
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright 2016 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

//! Dissection of User Datagram Protocol (UDP) packets.
//!
//! See [RFC 768](https://tools.ietf.org/html/rfc768).

use {
    Protocol,
    RawBytes,
    Result,
    Val,
    unsigned,
};

use byteorder::NetworkEndian;

/// Parser for the User Datagram Protocol (UDP).
pub struct UDP;

impl Protocol for UDP {
    fn short_name(&self) -> &'static str { "UDP" }
    fn full_name(&self) -> &'static str { "User Datagram Protocol" }

    fn dissect(&self, data : &[u8]) -> Result {
        let source = unsigned::<u16, NetworkEndian>(&data[0..2]);
        let dest = unsigned::<u16, NetworkEndian>(&data[2..4]);
        let length = unsigned::<u16, NetworkEndian>(&data[4..6]);
        let checksum = unsigned::<u16, NetworkEndian>(&data[6..8]);

        let protocol = match (&source,&dest) {
            (&Ok(_), &Ok(_)) => RawBytes::boxed("UNKNOWN", "unknown UDP protocol"),
            _ => RawBytes::unknown_protocol("UDP error"),
        };

        let values = vec![
                ("Source port", source.and_then(Val::base10)),
                ("Destination port", dest.and_then(Val::base10)),
                ("Length", length.and_then(Val::base10)),
                ("Checksum", checksum.and_then(Val::base16)),
                ("Data", protocol.dissect(&data[8..])),
            ]
            ;

        Ok(Val::Subpacket(values))
    }
}
<commit_msg>Start refactoring code to determine UDP protocol.<commit_after>/*
 * Copyright 2016 Jonathan Anderson
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://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.
 */

//! Dissection of User Datagram Protocol (UDP) packets.
//!
//! See [RFC 768](https://tools.ietf.org/html/rfc768).

use {
    Protocol,
    RawBytes,
    Result,
    Val,
    unsigned,
};

use byteorder::NetworkEndian;

/// Parser for the User Datagram Protocol (UDP).
pub struct UDP;

impl Protocol for UDP {
    fn short_name(&self) -> &'static str { "UDP" }
    fn full_name(&self) -> &'static str { "User Datagram Protocol" }

    fn dissect(&self, data : &[u8]) -> Result {
        let source = unsigned::<u16, NetworkEndian>(&data[0..2]);
        let dest = unsigned::<u16, NetworkEndian>(&data[2..4]);
        let length = unsigned::<u16, NetworkEndian>(&data[4..6]);
        let checksum = unsigned::<u16, NetworkEndian>(&data[6..8]);

        let protocol:Box<Protocol> = match (&source,&dest) {
            (&Ok(s), &Ok(d)) => protocol(s, d),
            _ => RawBytes::unknown_protocol("UDP error"),
        };

        let values = vec![
                ("Source port", source.and_then(Val::base10)),
                ("Destination port", dest.and_then(Val::base10)),
                ("Length", length.and_then(Val::base10)),
                ("Checksum", checksum.and_then(Val::base16)),
                ("Data", protocol.dissect(&data[8..])),
            ]
            ;

        Ok(Val::Subpacket(values))
    }
}

/// Find the UDP protocol that uses given source and destination ports.
pub fn protocol(source_port: u16, dest_port: u16) -> Box<Protocol> {
    match (source_port, dest_port) {
        (_, _) => RawBytes::boxed("UNKNOWN", "unknown UDP protocol"),
    }
}
<|endoftext|>


<commit_before>//! Interfaces for accessing and managing issues

// Third party
use url::form_urlencoded;

// Ours
use {Board, Issue, Jira, Result, SearchOptions};

/// issue options
#[derive(Debug)]
pub struct Issues {
    jira: Jira,
}

#[derive(Serialize, Debug)]
pub struct Assignee {
    pub name: String,
}

#[derive(Serialize, Debug)]
pub struct IssueType {
    pub id: String,
}

#[derive(Serialize, Debug)]
pub struct Priority {
    pub id: String,
}

#[derive(Serialize, Debug)]
pub struct Project {
    pub key: String,
}

#[derive(Serialize, Debug)]
pub struct Component {
    pub name: String,
}

#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Fields {
    pub assignee: Assignee,
    pub components: Vec<Component>,
    pub description: String,
    pub environment: String,
    pub issuetype: IssueType,
    pub priority: Priority,
    pub project: Project,
    pub reporter: Assignee,
    pub summary: String,
}

#[derive(Serialize, Debug)]
pub struct CreateIssue {
    pub fields: Fields,
}

#[derive(Debug, Deserialize)]
pub struct CreateResponse {
    pub id: String,
    pub key: String,
    #[serde(rename = "self")]
    pub url: String,
}

#[derive(Deserialize, Debug)]
pub struct Paginated<T> {
    pub expand: String,
    #[serde(rename = "maxResults")]
    pub max_results: u64,
    #[serde(rename = "startAt")]
    pub start_at: u64,
    pub total: u64,
    pub values: Vec<T>,
}

impl Issues {
    pub fn new(jira: &Jira) -> Issues {
        Issues { jira: jira.clone() }
    }

    pub fn get<I>(&self, id: I) -> Result<Issue>
    where
        I: Into<String>,
    {
        self.jira.get("api", &format!("/issue/{}", id.into()))
    }
    pub fn create(&self, data: CreateIssue) -> Result<CreateResponse> {
        self.jira.post("api", "/issue", data)
    }

    /// returns a single page of issues results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board-getIssuesForBoard
    pub fn list(&self, board: &Board, options: &SearchOptions) -> Result<Paginated<Issue>> {
        let mut path = vec![format!("/board/{}/issue", board.id)];
        let query_options = options.serialize().unwrap_or_default();
        let query = form_urlencoded::Serializer::new(query_options).finish();

        path.push(query);

        self.jira
            .get::<Paginated<Issue>>("agile", path.join("?").as_ref())
    }

    /// runs a type why may be used to iterate over consecutive pages of results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board-getIssuesForBoard
    pub fn iter<'a>(&self, board: &'a Board, options: &'a SearchOptions) -> Result<IssuesIter<'a>> {
        IssuesIter::new(board, options, &self.jira)
    }
}

/// provides an iterator over multiple pages of search results
#[derive(Debug)]
pub struct IssuesIter<'a> {
    jira: Jira,
    board: &'a Board,
    results: Paginated<Issue>,
    search_options: &'a SearchOptions,
}

impl<'a> IssuesIter<'a> {
    fn new(board: &'a Board, options: &'a SearchOptions, jira: &Jira) -> Result<Self> {
        let results = jira.issues().list(board, options)?;
        Ok(IssuesIter {
            board,
            jira: jira.clone(),
            results,
            search_options: options,
        })
    }

    fn more(&self) -> bool {
        (self.results.start_at + self.results.max_results) <= self.results.total
    }
}

impl<'a> Iterator for IssuesIter<'a> {
    type Item = Issue;
    fn next(&mut self) -> Option<Issue> {
        self.results.values.pop().or_else(|| {
            if self.more() {
                match self.jira.issues().list(
                    self.board,
                    &self
                        .search_options
                        .as_builder()
                        .max_results(self.results.max_results)
                        .start_at(self.results.start_at + self.results.max_results)
                        .build(),
                ) {
                    Ok(new_results) => {
                        self.results = new_results;
                        self.results.values.pop()
                    }
                    _ => None,
                }
            } else {
                None
            }
        })
    }
}
<commit_msg>as it was<commit_after>//! Interfaces for accessing and managing issues

// Third party
use url::form_urlencoded;

// Ours
use {Board, Issue, Jira, Result, SearchOptions};

/// issue options
#[derive(Debug)]
pub struct Issues {
    jira: Jira,
}

#[derive(Serialize, Debug)]
pub struct Assignee {
    pub name: String,
}

#[derive(Serialize, Debug)]
pub struct IssueType {
    pub id: String,
}

#[derive(Serialize, Debug)]
pub struct Priority {
    pub id: String,
}

#[derive(Serialize, Debug)]
pub struct Project {
    pub key: String,
}

#[derive(Serialize, Debug)]
pub struct Component {
    pub name: String,
}

#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Fields {
    pub assignee: Assignee,
    pub components: Vec<Component>,
    pub description: String,
    pub environment: String,
    pub issuetype: IssueType,
    pub priority: Priority,
    pub project: Project,
    pub reporter: Assignee,
    pub summary: String,
}

#[derive(Serialize, Debug)]
pub struct CreateIssue {
    pub fields: Fields,
}

#[derive(Debug, Deserialize)]
pub struct CreateResponse {
    pub id: String,
    pub key: String,
    #[serde(rename = "self")]
    pub url: String,
}

#[derive(Deserialize, Debug)]
pub struct IssueResults {
    pub expand: String,
    #[serde(rename = "maxResults")]
    pub max_results: u64,
    #[serde(rename = "startAt")]
    pub start_at: u64,
    pub total: u64,
    pub issues: Vec<Issue>,
}

impl Issues {
    pub fn new(jira: &Jira) -> Issues {
        Issues { jira: jira.clone() }
    }

    pub fn get<I>(&self, id: I) -> Result<Issue>
    where
        I: Into<String>,
    {
        self.jira.get("api", &format!("/issue/{}", id.into()))
    }
    pub fn create(&self, data: CreateIssue) -> Result<CreateResponse> {
        self.jira.post("api", "/issue", data)
    }

    /// returns a single page of issues results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board-getIssuesForBoard
    pub fn list(&self, board: &Board, options: &SearchOptions) -> Result<IssueResults> {
        let mut path = vec![format!("/board/{}/issue", board.id)];
        let query_options = options.serialize().unwrap_or_default();
        let query = form_urlencoded::Serializer::new(query_options).finish();

        path.push(query);

        self.jira
            .get::<IssueResults>("agile", path.join("?").as_ref())
    }

    /// runs a type why may be used to iterate over consecutive pages of results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board-getIssuesForBoard
    pub fn iter<'a>(&self, board: &'a Board, options: &'a SearchOptions) -> Result<IssuesIter<'a>> {
        IssuesIter::new(board, options, &self.jira)
    }
}

/// provides an iterator over multiple pages of search results
#[derive(Debug)]
pub struct IssuesIter<'a> {
    jira: Jira,
    board: &'a Board,
    results: IssueResults,
    search_options: &'a SearchOptions,
}

impl<'a> IssuesIter<'a> {
    fn new(board: &'a Board, options: &'a SearchOptions, jira: &Jira) -> Result<Self> {
        let results = jira.issues().list(board, options)?;
        Ok(IssuesIter {
            board,
            jira: jira.clone(),
            results,
            search_options: options,
        })
    }

    fn more(&self) -> bool {
        (self.results.start_at + self.results.max_results) <= self.results.total
    }
}

impl<'a> Iterator for IssuesIter<'a> {
    type Item = Issue;
    fn next(&mut self) -> Option<Issue> {
        self.results.issues.pop().or_else(|| {
            if self.more() {
                match self.jira.issues().list(
                    self.board,
                    &self
                        .search_options
                        .as_builder()
                        .max_results(self.results.max_results)
                        .start_at(self.results.start_at + self.results.max_results)
                        .build(),
                ) {
                    Ok(new_results) => {
                        self.results = new_results;
                        self.results.issues.pop()
                    }
                    _ => None,
                }
            } else {
                None
            }
        })
    }
}
<|endoftext|>