<commit_before>use cgmath;
use character::controls::CharacterInputState;
use game::constants::{ASPECT_RATIO, TILE_MAP_BUF_LENGTH};
use game::constants::{TILES_PCS_H, TILES_PCS_W};
use genmesh::{Triangulate, Vertices};
use genmesh::generators::{IndexedPolygon, Plane, SharedVertex};
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{can_move, Dimensions};
use graphics::{coords_to_tile, load_texture};
use graphics::camera::CameraInputState;
use shaders::{Position, Projection, tilemap_pipeline, TileMapData, TilemapSettings, VertexData};
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};

pub mod tile_map;

fn cartesian_to_isometric(point_x: f32, point_y: f32) -> (f32, f32) {
  ((point_x - point_y), (point_x + point_y) / 2.0)
}

#[derive(Debug)]
pub struct TerrainDrawable {
  projection: Projection,
  pub position: Position,
}

impl TerrainDrawable {
  pub fn new() -> TerrainDrawable {
    let view = Dimensions::get_view_matrix();
    TerrainDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(75.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position: Position::new([0.0, 0.0]),
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &mut CharacterInputState) {
    self.projection = *world_to_clip;
    let new_position = Position::new([ci.x_movement, ci.y_movement]);
    if can_move(new_position) {
      ci.is_colliding = false;
      self.position = new_position;
      coords_to_tile(self.position);
    } else {
      ci.is_colliding = true;
    }
  }
}

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

const SHADER_VERT: &[u8] = include_bytes!("../shaders/terrain.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/terrain.f.glsl");

pub struct TerrainDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, tilemap_pipeline::Data<R>>,
  data: Vec<TileMapData>,
  is_tile_map_dirty: bool,
}

impl<R: gfx::Resources> TerrainDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>)
                -> TerrainDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tile_size = 32;
    let width = TILES_PCS_W;
    let height = TILES_PCS_H;
    let half_width = (tile_size * width) / 2;
    let half_height = (tile_size * height) / 2;

    let tile_sheet_bytes = &include_bytes!("../../assets/maps/terrain.png")[..];
    let plane = Plane::subdivide(width, width);
    let vertex_data: Vec<VertexData> =
      plane.shared_vertex_iter()
           .map(|vertex| {
             let (raw_x, raw_y) = cartesian_to_isometric(vertex.pos[0], vertex.pos[1]);
             let vertex_x = half_width as f32 * raw_x;
             let vertex_y = half_height as f32 * raw_y;

             let (u_pos, v_pos) = ((raw_x / 4.0 - raw_y / 2.0) + 0.5, (raw_x / 4.0 + raw_y / 2.0) + 0.5);
             let tile_map_x = u_pos * width as f32;
             let tile_map_y = v_pos * height as f32;

             VertexData {
               pos: [vertex_x, vertex_y],
               buf_pos: [tile_map_x as f32, tile_map_y as f32],
             }
           })
           .collect();

    let index_data: Vec<u32> =
      plane.indexed_polygon_iter()
           .triangulate()
           .vertices()
           .map(|i| i as u32)
           .collect();

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let tile_texture = load_texture(factory, tile_sheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT, SHADER_FRAG, tilemap_pipeline::new())
      .unwrap();

    let pipeline_data = tilemap_pipeline::Data {
      vbuf: vertex_buf,
      position_cb: factory.create_constant_buffer(1),
      projection_cb: factory.create_constant_buffer(1),
      tilemap: factory.create_constant_buffer(TILE_MAP_BUF_LENGTH),
      tilemap_cb: factory.create_constant_buffer(1),
      tilesheet: (tile_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let terrain = tile_map::Terrain::new();

    TerrainDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: terrain.tiles,
      is_tile_map_dirty: true,
    }
  }

  pub fn draw<C>(&mut self,
                 drawable: &TerrainDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    if self.is_tile_map_dirty {
      encoder.update_buffer(&self.bundle.data.tilemap, self.data.as_slice(), 0).unwrap();
      encoder.update_constant_buffer(&self.bundle.data.tilemap_cb, &TilemapSettings {
        world_size: [64.0, 64.0],
        tilesheet_size: [32.0, 32.0],
      });
      self.is_tile_map_dirty = false
    }

    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  type SystemData = (WriteStorage<'a, TerrainDrawable>,
                     ReadStorage<'a, CameraInputState>,
                     WriteStorage<'a, CharacterInputState>,
                     Fetch<'a, Dimensions>);

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

    for (t, camera, ci) in (&mut terrain, &camera_input, &mut character_input).join() {
      let world_to_clip = dim.world_to_projection(camera);
      t.update(&world_to_clip, ci);
    }
  }
}
<commit_msg>Readjust terrain projection<commit_after>use cgmath;
use character::controls::CharacterInputState;
use game::constants::{ASPECT_RATIO, TILE_MAP_BUF_LENGTH};
use game::constants::{TILES_PCS_H, TILES_PCS_W};
use genmesh::{Triangulate, Vertices};
use genmesh::generators::{IndexedPolygon, Plane, SharedVertex};
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{can_move, Dimensions};
use graphics::{coords_to_tile, load_texture};
use graphics::camera::CameraInputState;
use shaders::{Position, Projection, tilemap_pipeline, TileMapData, TilemapSettings, VertexData};
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};

pub mod tile_map;

fn cartesian_to_isometric(point_x: f32, point_y: f32) -> (f32, f32) {
  ((point_x - point_y), (point_x + point_y) / 1.78)
}

#[derive(Debug)]
pub struct TerrainDrawable {
  projection: Projection,
  pub position: Position,
}

impl TerrainDrawable {
  pub fn new() -> TerrainDrawable {
    let view = Dimensions::get_view_matrix();
    TerrainDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(75.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position: Position::new([0.0, 0.0]),
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &mut CharacterInputState) {
    self.projection = *world_to_clip;
    let new_position = Position::new([ci.x_movement, ci.y_movement]);
    if can_move(new_position) {
      ci.is_colliding = false;
      self.position = new_position;
      coords_to_tile(self.position);
    } else {
      ci.is_colliding = true;
    }
  }
}

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

const SHADER_VERT: &[u8] = include_bytes!("../shaders/terrain.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/terrain.f.glsl");

pub struct TerrainDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, tilemap_pipeline::Data<R>>,
  data: Vec<TileMapData>,
  is_tile_map_dirty: bool,
}

impl<R: gfx::Resources> TerrainDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>)
                -> TerrainDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let tile_size = 32;
    let width = TILES_PCS_W;
    let height = TILES_PCS_H;
    let half_width = (tile_size * width) / 2;
    let half_height = (tile_size * height) / 2;

    let tile_sheet_bytes = &include_bytes!("../../assets/maps/terrain.png")[..];
    let plane = Plane::subdivide(width, width);
    let vertex_data: Vec<VertexData> =
      plane.shared_vertex_iter()
           .map(|vertex| {
             let (raw_x, raw_y) = cartesian_to_isometric(vertex.pos[0], vertex.pos[1]);
             let vertex_x = half_width as f32 * raw_x;
             let vertex_y = half_height as f32 * raw_y;

             let (u_pos, v_pos) = ((raw_x / 4.0 - raw_y / 2.25) + 0.5, (raw_x / 4.0 + raw_y / 2.25) + 0.5);
             let tile_map_x = u_pos * width as f32;
             let tile_map_y = v_pos * height as f32;

             VertexData {
               pos: [vertex_x, vertex_y],
               buf_pos: [tile_map_x as f32, tile_map_y as f32],
             }
           })
           .collect();

    let index_data: Vec<u32> =
      plane.indexed_polygon_iter()
           .triangulate()
           .vertices()
           .map(|i| i as u32)
           .collect();

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let tile_texture = load_texture(factory, tile_sheet_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT, SHADER_FRAG, tilemap_pipeline::new())
      .unwrap();

    let pipeline_data = tilemap_pipeline::Data {
      vbuf: vertex_buf,
      position_cb: factory.create_constant_buffer(1),
      projection_cb: factory.create_constant_buffer(1),
      tilemap: factory.create_constant_buffer(TILE_MAP_BUF_LENGTH),
      tilemap_cb: factory.create_constant_buffer(1),
      tilesheet: (tile_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let terrain = tile_map::Terrain::new();

    TerrainDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data: terrain.tiles,
      is_tile_map_dirty: true,
    }
  }

  pub fn draw<C>(&mut self,
                 drawable: &TerrainDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    if self.is_tile_map_dirty {
      encoder.update_buffer(&self.bundle.data.tilemap, self.data.as_slice(), 0).unwrap();
      encoder.update_constant_buffer(&self.bundle.data.tilemap_cb, &TilemapSettings {
        world_size: [64.0, 64.0],
        tilesheet_size: [32.0, 32.0],
      });
      self.is_tile_map_dirty = false
    }

    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  type SystemData = (WriteStorage<'a, TerrainDrawable>,
                     ReadStorage<'a, CameraInputState>,
                     WriteStorage<'a, CharacterInputState>,
                     Fetch<'a, Dimensions>);

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

    for (t, camera, ci) in (&mut terrain, &camera_input, &mut character_input).join() {
      let world_to_clip = dim.world_to_projection(camera);
      t.update(&world_to_clip, ci);
    }
  }
}
<|endoftext|>


<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  fn from_i8(sample: i8) -> Self;
  fn from_i16(sample: i16) -> Self;
  fn from_i32(sample: i32) -> Option<Self>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<commit_msg>Add documentation for `Sample::from_i8`<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;
  fn from_i16(sample: i16) -> Self;
  fn from_i32(sample: i32) -> Option<Self>;
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }
}
<|endoftext|>


<commit_before>//! This module provides implementations of Option's methods for objects that are sufficiently
//! like Options. This modules is a candidate to be put in its own crate.
//!
//! Most of the examples for these methods were adapted from the `std::option` examples.
//!
//! # Example
//!
//! ```
//! use checked::AsRefOption;
//!
//! struct OptionWrapper<T>(Option<T>);
//!
//! impl<T> AsRef<Option<T>> for OptionWrapper<T> {
//!     fn as_ref(&self) -> &Option<T>{
//!         &self.0
//!     }
//! }
//!
//! impl<T> AsRefOption<T> for OptionWrapper<T> {}
//!
//! let x = OptionWrapper(Some(5_i32)); // x is an OptionWrapper<i32>
//!
//! // We can now use some of Option's methods on x directly.
//! assert!(x.is_some());
//! ```

use std::option::{Iter, IterMut};

// These impls don't seem to work as intended.
// impl<T, U> IntoOption<T> for U
// where
//     U: Into<Option<T>>,
// {
// }
//
// impl<T, U> AsRefOption<T> for U
// where
//     U: AsRef<Option<T>>,
// {
// }
//
// impl<T, U> AsMutOption<T> for U
// where
//     U: AsMut<Option<T>>,
// {
// }

/// The `IntoOption` trait implements all the methods of `Option` that consume self.
pub trait IntoOption<T>: Into<Option<T>> {
    /// Unwraps an option-like, yielding the content of a `Some`.
    ///
    /// # Panics
    ///
    /// Panics if the value is a `None` with a custom panic message provided by
    /// `msg`.
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use checked::{Checked, IntoOption};
    ///
    /// let x = Checked::from(5_i32);
    /// assert_eq!(x.expect("the world is ending"), 5);
    /// ```
    ///
    /// ```{.should_panic}
    /// use checked::{Checked, IntoOption};
    ///
    /// let x: Checked<&str> = Checked(None);
    /// x.expect("the world is ending"); // panics with `the world is ending`
    /// ```
    fn expect(self, msg: &str) -> T {
        <Self as Into<Option<T>>>::into(self).expect(msg)
    }

    /// Moves the value `v` out of the `Option<T>` if it is `Some(v)`.
    ///
    /// In general, because this function may panic, its use is discouraged.
    /// Instead, prefer to use pattern matching and handle the `None`
    /// case explicitly.
    ///
    /// # Panics
    ///
    /// Panics if the self value equals `None`.
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use checked::{Checked, IntoOption};
    ///
    /// let x = Checked(Some("air"));
    /// assert_eq!(x.unwrap(), "air");
    /// ```
    ///
    /// ```{.should_panic}
    /// use checked::{Checked, IntoOption};
    ///
    /// let x: Checked<&str> = Checked(None);
    /// assert_eq!(x.unwrap(), "air"); // fails
    /// ```
    fn unwrap(self) -> T {
        <Self as Into<Option<T>>>::into(self).unwrap()
    }

    /// Returns the contained value or a default.
    ///
    /// # Examples
    ///
    /// ```
    /// use checked::{Checked, IntoOption};
    ///
    /// assert_eq!(Checked(Some("car")).unwrap_or("bike"), "car");
    /// assert_eq!(Checked(None).unwrap_or("bike"), "bike");
    /// ```
    fn unwrap_or(self, def: T) -> T {
        <Self as Into<Option<T>>>::into(self).unwrap_or(def)
    }

    fn unwrap_or_else<F>(self, f: F) -> T
    where
        F: FnOnce() -> T,
    {
        <Self as Into<Option<T>>>::into(self).unwrap_or_else(f)
    }

    fn map<U, F>(self, f: F) -> Option<U>
    where
        F: FnOnce(T) -> U,
    {
        <Self as Into<Option<T>>>::into(self).map(f)
    }

    fn map_or<U, F>(self, default: U, f: F) -> U
    where
        F: FnOnce(T) -> U,
    {
        <Self as Into<Option<T>>>::into(self).map_or(default, f)
    }

    fn map_or_else<U, D, F>(self, default: D, f: F) -> U
    where
        D: FnOnce() -> U,
        F: FnOnce(T) -> U,
    {
        <Self as Into<Option<T>>>::into(self).map_or_else(default, f)
    }

    fn ok_or<E>(self, err: E) -> Result<T, E> {
        <Self as Into<Option<T>>>::into(self).ok_or(err)
    }

    fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
    where
        F: FnOnce() -> E,
    {
        <Self as Into<Option<T>>>::into(self).ok_or_else(err)
    }

    fn and<U>(self, optb: Option<U>) -> Option<U> {
        <Self as Into<Option<T>>>::into(self).and(optb)
    }

    fn and_then<U, F>(self, f: F) -> Option<U>
    where
        F: FnOnce(T) -> Option<U>,
    {
        <Self as Into<Option<T>>>::into(self).and_then(f)
    }

    fn or(self, optb: Option<T>) -> Option<T> {
        <Self as Into<Option<T>>>::into(self).or(optb)
    }

    fn or_else<F>(self, f: F) -> Option<T>
    where
        F: FnOnce() -> Option<T>,
    {
        <Self as Into<Option<T>>>::into(self).or_else(f)
    }
}

/// The `AsRefOption` trait implements all the methods of `Option` that take an immutable reference
/// to self.
pub trait AsRefOption<T>: AsRef<Option<T>> {
    fn is_some(&self) -> bool {
        <Self as AsRef<Option<T>>>::as_ref(self).is_some()
    }

    fn is_none(&self) -> bool {
        <Self as AsRef<Option<T>>>::as_ref(self).is_none()
    }

    fn as_ref(&self) -> Option<&T> {
        <Self as AsRef<Option<T>>>::as_ref(self).as_ref()
    }

    fn iter(&self) -> Iter<T> {
        <Self as AsRef<Option<T>>>::as_ref(self).iter()
    }
}

/// The `AsMutOption` trait implements all the methods of `Option` that take a mutable reference to
/// self.
pub trait AsMutOption<T>: AsMut<Option<T>> {
    fn as_mut(&mut self) -> Option<&mut T> {
        <Self as AsMut<Option<T>>>::as_mut(self).as_mut()
    }

    fn iter_mut(&mut self) -> IterMut<T> {
        <Self as AsMut<Option<T>>>::as_mut(self).iter_mut()
    }

    #[cfg(feature = "option_entry")]
    fn get_or_insert(&mut self, v: T) -> &mut T {
        <Self as AsMut<Option<T>>>::as_mut(self).get_or_insert(v)
    }

    #[cfg(feature = "option_entry")]
    fn get_or_insert_with<F>(&mut self, f: F) -> &mut T
    where
        F: FnOnce() -> T,
    {
        <Self as AsMut<Option<T>>>::as_mut(self).get_or_insert_with(f)
    }

    fn take(&mut self) -> Option<T> {
        <Self as AsMut<Option<T>>>::as_mut(self).take()
    }
}
<commit_msg>The Deref and DerefMut traits fit better<commit_after><|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use mimir;
use mimir::Members;
use std::path::Path;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper);
}

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test_sqlite(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            "--db-file=test-db.sqlite3".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper);
}

fn check_results(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    // Test: Import of Admin
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Livry-sur-Seine", |_| true)
        .collect();
    assert_eq!(res.len(), 5);

    let has_boundary = |res: &Vec<mimir::Place>, is_admin: bool| {
        res.iter()
            .filter(|place| place.is_admin() == is_admin)
            .flat_map(|a| a.admins())
            .all(|a| a.boundary.clone().map_or(false, |b| !b.0.is_empty()))
    };
    // Admins have boundaries
    assert!(has_boundary(&res, true));

    // Others places than Admin don't
    assert!(!has_boundary(&res, false));

    assert!(res.iter().any(|r| r.is_admin()));

    // Test that Créteil (admin_level 7) is not treated as a city (level 8)
    let admin_regions: Vec<_> = es_wrapper
        .search_and_filter("label:Créteil", |_| true)
        .collect();
    assert!(admin_regions.len() >= 1);
    if let mimir::Place::Admin(ref creteil) = admin_regions[0] {
        assert_eq!(creteil.name, "Créteil");
        assert_eq!(creteil.level, 7);
        assert!(creteil.zone_type.is_none());
    } else {
        panic!("creteil should be an admin");
    }

    // Test: search for "Rue des Près"
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue des Près", |_| true)
        .collect();
    assert!(res.len() != 0);
    assert!(res[0].is_street());
    // The first hit should be "Rue des Près"
    assert_eq!(res[0].label(), "Rue des Près (Livry-sur-Seine)");

    // And there should be only ONE "Rue des Près"
    assert_eq!(
        res.iter()
            .filter(|place| place.is_street() && place.label() == "Rue des Près (Livry-sur-Seine)")
            .count(),
        1
    );

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Four à Chaux (Livry-sur-Seine)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Livry-sur-Seine (77000)")
                .unwrap_or(false)
    };
    // As we merge all ways with same name and of the same admin(level=city_level)
    // Here we have only one way
    let four_a_chaux_street: Vec<mimir::Place> = es_wrapper
        .search_and_filter("label:Rue du Four à Chaux (Livry-sur-Seine)", place_filter)
        .collect();

    let nb = four_a_chaux_street.len();
    assert_eq!(nb, 1);

    // Test the id is the min(=40812939) of all the ways composing the street
    assert!(four_a_chaux_street[0].address().map_or(false, |a| {
        if let mimir::Address::Street(s) = a {
            s.id == "street:osm:way:40812939"
        } else {
            false
        }
    }));

    // Test: Streets having the same label in different cities
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Port (Melun)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Melun (77000-CP77001)")
                .unwrap_or(false)
    };
    let nb = es_wrapper
        .search_and_filter("label:Rue du Port (Melun)", place_filter)
        .count();
    assert_eq!(nb, 1);

    // Test: Street admin is based on a middle node
    // (instead of the first node which is located outside Melun)
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue Marcel Houdet", |_| true)
        .collect();
    assert!(res.len() != 0);
    assert_eq!(res[0].label(), "Rue Marcel Houdet (Melun)");
    assert!(res[0]
        .admins()
        .iter()
        .filter(|a| a.is_city())
        .any(|a| a.name == "Melun"));

    // Test: search Pois by label
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Le-Mée-sur-Seine Courtilleraies", |_| true)
        .collect();
    assert!(res.len() != 0);

    let poi_type_post_office = "poi_type:amenity:post_office";
    assert!(res.iter().any(|r| r
        .poi()
        .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)));

    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Melun Rp", |_| true)
        .collect();
    assert!(res.len() != 0);
    assert!(res.iter().any(|r| r
        .poi()
        .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)));
}
<commit_msg>add tests for sqlite backend as well<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

use mimir;
use mimir::Members;
use std::path::Path;

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper, "btreemap backend");
}

/// Simple call to a BANO load into ES base
/// Checks that we are able to find one object (a specific address)
pub fn osm2mimir_sample_test_sqlite(es_wrapper: crate::ElasticSearchWrapper<'_>) {
    let osm2mimir = Path::new(env!("OUT_DIR"))
        .join("../../../osm2mimir")
        .display()
        .to_string();
    crate::launch_and_assert(
        &osm2mimir,
        &[
            "--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
            "--import-way".into(),
            "--import-admin".into(),
            "--import-poi".into(),
            "--level=8".into(),
            "--level=7".into(),
            "--db-file=test-db.sqlite3".into(),
            format!("--connection-string={}", es_wrapper.host()),
        ],
        &es_wrapper,
    );

    check_results(es_wrapper, "sqlite backend");
}

fn check_results(es_wrapper: crate::ElasticSearchWrapper<'_>, test_name: &str) {
    // Test: Import of Admin
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Livry-sur-Seine", |_| true)
        .collect();
    assert_eq!(res.len(), 5, "{}", test_name);

    let has_boundary = |res: &Vec<mimir::Place>, is_admin: bool| {
        res.iter()
            .filter(|place| place.is_admin() == is_admin)
            .flat_map(|a| a.admins())
            .all(|a| a.boundary.clone().map_or(false, |b| !b.0.is_empty()))
    };
    // Admins have boundaries
    assert!(has_boundary(&res, true), "{}", test_name);

    // Others places than Admin don't
    assert!(!has_boundary(&res, false), "{}", test_name);

    assert!(res.iter().any(|r| r.is_admin()), "{}", test_name);

    // Test that Créteil (admin_level 7) is not treated as a city (level 8)
    let admin_regions: Vec<_> = es_wrapper
        .search_and_filter("label:Créteil", |_| true)
        .collect();
    assert!(admin_regions.len() >= 1, "{}", test_name);
    if let mimir::Place::Admin(ref creteil) = admin_regions[0] {
        assert_eq!(creteil.name, "Créteil", "{}", test_name);
        assert_eq!(creteil.level, 7, "{}", test_name);
        assert!(creteil.zone_type.is_none(), "{}", test_name);
    } else {
        panic!("creteil should be an admin");
    }

    // Test: search for "Rue des Près"
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue des Près", |_| true)
        .collect();
    assert!(res.len() != 0, "{}", test_name);
    assert!(res[0].is_street(), "{}", test_name);
    // The first hit should be "Rue des Près"
    assert_eq!(res[0].label(), "Rue des Près (Livry-sur-Seine)", "{}", test_name);

    // And there should be only ONE "Rue des Près"
    assert_eq!(
        res.iter()
            .filter(|place| place.is_street() && place.label() == "Rue des Près (Livry-sur-Seine)")
            .count(),
        1,
        "{}",
        test_name
    );

    // Test: Search for "Rue du Four à Chaux" in "Livry-sur-Seine"
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Four à Chaux (Livry-sur-Seine)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Livry-sur-Seine (77000)")
                .unwrap_or(false)
    };
    // As we merge all ways with same name and of the same admin(level=city_level)
    // Here we have only one way
    let four_a_chaux_street: Vec<mimir::Place> = es_wrapper
        .search_and_filter("label:Rue du Four à Chaux (Livry-sur-Seine)", place_filter)
        .collect();

    let nb = four_a_chaux_street.len();
    assert_eq!(nb, 1, "{}", test_name);

    // Test the id is the min(=40812939) of all the ways composing the street
    assert!(four_a_chaux_street[0].address().map_or(false, |a| {
        if let mimir::Address::Street(s) = a {
            s.id == "street:osm:way:40812939"
        } else {
            false
        }
    }), "{}", test_name);

    // Test: Streets having the same label in different cities
    let place_filter = |place: &mimir::Place| {
        place.is_street()
            && place.label() == "Rue du Port (Melun)"
            && place
                .admins()
                .first()
                .map(|admin| admin.label() == "Melun (77000-CP77001)")
                .unwrap_or(false)
    };
    let nb = es_wrapper
        .search_and_filter("label:Rue du Port (Melun)", place_filter)
        .count();
    assert_eq!(nb, 1, "{}", test_name);

    // Test: Street admin is based on a middle node
    // (instead of the first node which is located outside Melun)
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Rue Marcel Houdet", |_| true)
        .collect();
    assert!(res.len() != 0, "{}", test_name);
    assert_eq!(res[0].label(), "Rue Marcel Houdet (Melun)", "{}", test_name);
    assert!(res[0]
        .admins()
        .iter()
        .filter(|a| a.is_city())
        .any(|a| a.name == "Melun"));

    // Test: search Pois by label
    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Le-Mée-sur-Seine Courtilleraies", |_| true)
        .collect();
    assert!(res.len() != 0, "{}", test_name);

    let poi_type_post_office = "poi_type:amenity:post_office";
    assert!(res.iter().any(|r| r
        .poi()
        .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)), "{}", test_name);

    let res: Vec<_> = es_wrapper
        .search_and_filter("label:Melun Rp", |_| true)
        .collect();
    assert!(res.len() != 0, "{}", test_name);
    assert!(res.iter().any(|r| r
        .poi()
        .map_or(false, |poi| poi.poi_type.id == poi_type_post_office)), "{}", test_name);
}
<|endoftext|>


<commit_before>/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
/// type inference to figure out a return type for those tokens.
///
/// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
///
/// The return type can be any syntax tree node that implements the [`Parse`]
/// trait.
///
/// [`Parse`]: parse::Parse
///
/// ```
/// use quote::quote;
/// use syn::{parse_quote, Stmt};
///
/// fn main() {
///     let name = quote!(v);
///     let ty = quote!(u8);
///
///     let stmt: Stmt = parse_quote! {
///         let #name: #ty = Default::default();
///     };
///
///     println!("{:#?}", stmt);
/// }
/// ```
///
/// *This macro is available if Syn is built with the `"parsing"` feature,
/// although interpolation of syntax tree nodes into the quoted tokens is only
/// supported if Syn is built with the `"printing"` feature as well.*
///
/// # Example
///
/// The following helper function adds a bound `T: HeapSize` to every type
/// parameter `T` in the input generics.
///
/// ```
/// use syn::{parse_quote, Generics, GenericParam};
///
/// // Add a bound `T: HeapSize` to every type parameter T.
/// fn add_trait_bounds(mut generics: Generics) -> Generics {
///     for param in &mut generics.params {
///         if let GenericParam::Type(type_param) = param {
///             type_param.bounds.push(parse_quote!(HeapSize));
///         }
///     }
///     generics
/// }
/// ```
///
/// # Special cases
///
/// This macro can parse the following additional types as a special case even
/// though they do not implement the `Parse` trait.
///
/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
///   or inner like `#![...]`
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
///   `P` with optional trailing punctuation
///
/// [`Punctuated<T, P>`]: punctuated::Punctuated
///
/// # Panics
///
/// Panics if the tokens fail to parse as the expected syntax tree type. The
/// caller is responsible for ensuring that the input tokens are syntactically
/// valid.
//
// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
// https://github.com/rust-lang/rust/issues/62834
#[macro_export(local_inner_macros)]
macro_rules! parse_quote {
    ($($tt:tt)*) => {
        $crate::parse_quote::parse(
            $crate::export::From::from(
                $crate::export::quote::quote!($($tt)*)
            )
        )
    };
}

////////////////////////////////////////////////////////////////////////////////
// Can parse any type that implements Parse.

use crate::parse::{Parse, ParseStream, Parser, Result};
use proc_macro2::TokenStream;

// Not public API.
#[doc(hidden)]
pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
    let parser = T::parse;
    match parser.parse2(token_stream) {
        Ok(t) => t,
        Err(err) => panic!("{}", err),
    }
}

// Not public API.
#[doc(hidden)]
pub trait ParseQuote: Sized {
    fn parse(input: ParseStream) -> Result<Self>;
}

impl<T: Parse> ParseQuote for T {
    fn parse(input: ParseStream) -> Result<Self> {
        <T as Parse>::parse(input)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Any other types that we want `parse_quote!` to be able to parse.

use crate::punctuated::Punctuated;
#[cfg(any(feature = "full", feature = "derive"))]
use crate::{attr, Attribute};

#[cfg(any(feature = "full", feature = "derive"))]
impl ParseQuote for Attribute {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Token![#]) && input.peek2(Token![!]) {
            attr::parsing::single_parse_inner(input)
        } else {
            attr::parsing::single_parse_outer(input)
        }
    }
}

impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
    fn parse(input: ParseStream) -> Result<Self> {
        Self::parse_terminated(input)
    }
}
<commit_msg>Allow parse_quote to parse Vec<Stmt><commit_after>/// Quasi-quotation macro that accepts input like the [`quote!`] macro but uses
/// type inference to figure out a return type for those tokens.
///
/// [`quote!`]: https://docs.rs/quote/1.0/quote/index.html
///
/// The return type can be any syntax tree node that implements the [`Parse`]
/// trait.
///
/// [`Parse`]: parse::Parse
///
/// ```
/// use quote::quote;
/// use syn::{parse_quote, Stmt};
///
/// fn main() {
///     let name = quote!(v);
///     let ty = quote!(u8);
///
///     let stmt: Stmt = parse_quote! {
///         let #name: #ty = Default::default();
///     };
///
///     println!("{:#?}", stmt);
/// }
/// ```
///
/// *This macro is available if Syn is built with the `"parsing"` feature,
/// although interpolation of syntax tree nodes into the quoted tokens is only
/// supported if Syn is built with the `"printing"` feature as well.*
///
/// # Example
///
/// The following helper function adds a bound `T: HeapSize` to every type
/// parameter `T` in the input generics.
///
/// ```
/// use syn::{parse_quote, Generics, GenericParam};
///
/// // Add a bound `T: HeapSize` to every type parameter T.
/// fn add_trait_bounds(mut generics: Generics) -> Generics {
///     for param in &mut generics.params {
///         if let GenericParam::Type(type_param) = param {
///             type_param.bounds.push(parse_quote!(HeapSize));
///         }
///     }
///     generics
/// }
/// ```
///
/// # Special cases
///
/// This macro can parse the following additional types as a special case even
/// though they do not implement the `Parse` trait.
///
/// - [`Attribute`] — parses one attribute, allowing either outer like `#[...]`
///   or inner like `#![...]`
/// - [`Punctuated<T, P>`] — parses zero or more `T` separated by punctuation
///   `P` with optional trailing punctuation
/// - [`Vec<Stmt>`] — parses the same as `Block::parse_within`
///
/// [`Punctuated<T, P>`]: punctuated::Punctuated
/// [`Vec<Stmt>`]: Block::parse_within
///
/// # Panics
///
/// Panics if the tokens fail to parse as the expected syntax tree type. The
/// caller is responsible for ensuring that the input tokens are syntactically
/// valid.
//
// TODO: allow Punctuated to be inferred as intra doc link, currently blocked on
// https://github.com/rust-lang/rust/issues/62834
#[macro_export(local_inner_macros)]
macro_rules! parse_quote {
    ($($tt:tt)*) => {
        $crate::parse_quote::parse(
            $crate::export::From::from(
                $crate::export::quote::quote!($($tt)*)
            )
        )
    };
}

////////////////////////////////////////////////////////////////////////////////
// Can parse any type that implements Parse.

use crate::parse::{Parse, ParseStream, Parser, Result};
use proc_macro2::TokenStream;

// Not public API.
#[doc(hidden)]
pub fn parse<T: ParseQuote>(token_stream: TokenStream) -> T {
    let parser = T::parse;
    match parser.parse2(token_stream) {
        Ok(t) => t,
        Err(err) => panic!("{}", err),
    }
}

// Not public API.
#[doc(hidden)]
pub trait ParseQuote: Sized {
    fn parse(input: ParseStream) -> Result<Self>;
}

impl<T: Parse> ParseQuote for T {
    fn parse(input: ParseStream) -> Result<Self> {
        <T as Parse>::parse(input)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Any other types that we want `parse_quote!` to be able to parse.

use crate::punctuated::Punctuated;
#[cfg(any(feature = "full", feature = "derive"))]
use crate::{attr, Attribute};
#[cfg(feature = "full")]
use crate::{Block, Stmt};

#[cfg(any(feature = "full", feature = "derive"))]
impl ParseQuote for Attribute {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Token![#]) && input.peek2(Token![!]) {
            attr::parsing::single_parse_inner(input)
        } else {
            attr::parsing::single_parse_outer(input)
        }
    }
}

impl<T: Parse, P: Parse> ParseQuote for Punctuated<T, P> {
    fn parse(input: ParseStream) -> Result<Self> {
        Self::parse_terminated(input)
    }
}

#[cfg(feature = "full")]
impl ParseQuote for Vec<Stmt> {
    fn parse(input: ParseStream) -> Result<Self> {
        Block::parse_within(input)
    }
}
<|endoftext|>


<commit_before>use uuid::Uuid;

pub fn allocate_element_key() -> String {
    let uuid_ = format!("{}", Uuid::new_v4());
    format!("{0:.8}", uuid_)
}
<commit_msg>Reduce length of generated element key components to 3 chars.<commit_after>use uuid::Uuid;

pub fn allocate_element_key() -> String {
    let uuid_ = format!("{}", Uuid::new_v4());
    format!("{0:.3}", uuid_)
}
<|endoftext|>


<commit_before>use super::gl;
use super::Context;
use std::mem;
use std::raw;

pub trait VertexData: Copy {
    type Binder: VertexAttribBinder;
}

pub trait VertexAttribBinder {
    type Builder;

    fn build() -> Self::Builder;

    fn bind(&mut self, gl: Context);
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy)]
pub enum DataType {
    BYTE = gl::BYTE as isize,
    UNSIGNED_BYTE = gl::UNSIGNED_BYTE as isize,
    SHORT = gl::SHORT as isize,
    UNSIGNED_SHORT = gl::UNSIGNED_SHORT as isize,
    FIXED = gl::FIXED as isize,
    FLOAT = gl::FLOAT as isize
}
pub use self::DataType::*;

pub trait VertexPrimitive {
    fn gl_type() -> DataType;
}

impl VertexPrimitive for i8 {
    fn gl_type() -> DataType { self::BYTE }
}

impl VertexPrimitive for u8 {
    fn gl_type() -> DataType { self::UNSIGNED_BYTE }
}

impl VertexPrimitive for i16 {
    fn gl_type() -> DataType { self::SHORT }
}

impl VertexPrimitive for u16 {
    fn gl_type() -> DataType { self::UNSIGNED_SHORT }
}

impl VertexPrimitive for f32 {
    fn gl_type() -> DataType { self::FLOAT }
}

pub trait VertexDatum {
    fn gl_type() -> DataType;
    fn components() -> i8;
    fn normalized() -> bool { false }
}

impl<T> VertexDatum for T where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

impl<T> VertexDatum for [T; 1] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

impl<T> VertexDatum for [T; 2] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 2 }
}

impl<T> VertexDatum for [T; 3] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 3 }
}

impl<T> VertexDatum for [T; 4] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 4 }
}

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<Self> {
                data: self,
                len: mem::size_of::<Self>()
            })
        }
    }
}

#[macro_export]
macro_rules! vertex_data {
    ($(
        struct $name:ident {
            $($field_name:ident: $field_type:ty),*
        }
    )+) => {
        mod _glitter_vertex_data {
            $(
                #[allow(non_snake_case)]
                pub mod $name {
                    #[repr(C)]
                    #[derive(Debug, Clone, Copy)]
                    pub struct $name {
                        $($field_name: $field_type),*
                    }

                    pub struct Binder;

                    impl $crate::VertexData for $name {
                        type Binder = Binder;
                    }
                }
            )+
        }

        $(
            #[allow(unused_imports)]
            use self::_glitter_vertex_data::$name::$name;
        )+
    }
}
<commit_msg>Rework `vertex_data!` macro<commit_after>use super::gl;
use super::Context;
use std::mem;
use std::raw;

pub trait VertexData: Copy {
    type Binder: VertexAttribBinder;

    fn build_attrib_binder() -> <Self::Binder as VertexAttribBinder>::Builder;
}

pub trait VertexAttribBinder {
    type Builder;

    fn bind(&self, gl: &Context);
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy)]
pub enum DataType {
    BYTE = gl::BYTE as isize,
    UNSIGNED_BYTE = gl::UNSIGNED_BYTE as isize,
    SHORT = gl::SHORT as isize,
    UNSIGNED_SHORT = gl::UNSIGNED_SHORT as isize,
    FIXED = gl::FIXED as isize,
    FLOAT = gl::FLOAT as isize
}
pub use self::DataType::*;

pub trait VertexPrimitive {
    fn gl_type() -> DataType;
}

impl VertexPrimitive for i8 {
    fn gl_type() -> DataType { self::BYTE }
}

impl VertexPrimitive for u8 {
    fn gl_type() -> DataType { self::UNSIGNED_BYTE }
}

impl VertexPrimitive for i16 {
    fn gl_type() -> DataType { self::SHORT }
}

impl VertexPrimitive for u16 {
    fn gl_type() -> DataType { self::UNSIGNED_SHORT }
}

impl VertexPrimitive for f32 {
    fn gl_type() -> DataType { self::FLOAT }
}

pub trait VertexDatum {
    fn gl_type() -> DataType;
    fn components() -> i8;
    fn normalized() -> bool { false }
}

impl<T> VertexDatum for T where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

impl<T> VertexDatum for [T; 1] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

impl<T> VertexDatum for [T; 2] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 2 }
}

impl<T> VertexDatum for [T; 3] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 3 }
}

impl<T> VertexDatum for [T; 4] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 4 }
}

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<Self> {
                data: self,
                len: mem::size_of::<Self>()
            })
        }
    }
}

impl<T> VertexBytes for [T] where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            mem::transmute(raw::Slice::<T> {
                data: &self[0],
                len: mem::size_of::<T>() * self.len()
            })
        }
    }
}

// TODO: Use a proper compiler intrinsic/macro (when available)
// see: https://github.com/rust-lang/rust/issues/24111
#[macro_export]
macro_rules! offset_of {
    ($T:ty, $field:ident) => {
        unsafe {
            use std::mem::{uninitialized, transmute};

            let obj : $T = uninitialized();
            let obj_ptr : *const u8 = transmute(&obj);
            let member_ptr : *const u8 = transmute(&obj.$field);

            (member_ptr as usize) - (obj_ptr as usize)
        }
    }
}

#[macro_use(offset_of)]
#[macro_export]
macro_rules! vertex_data {
    ($(
        struct $name:ident {
            $($field_name:ident: $field_type:ty),*
        }
    )+) => {
        mod _glitter_vertex_data {$(
            #[allow(non_snake_case)]
            pub mod $name {
                #[repr(C)]
                #[derive(Debug, Clone, Copy)]
                pub struct $name {
                    $(pub $field_name: $field_type),*
                }

                impl $crate::VertexData for $name {
                    type Binder = Binder;

                    fn build_attrib_binder() -> BinderBuilder {
                        BinderBuilder::new()
                    }
                }

                #[allow(dead_code)]
                pub struct Binder {
                    $($field_name: $crate::ProgramAttrib),*
                }

                impl $crate::VertexAttribBinder for Binder {
                    type Builder = BinderBuilder;

                    fn bind(&self, gl: &$crate::Context) {
                        use std::mem;
                        use $crate::VertexDatum as Datum;

                        $({
                            let components =
                                <$field_type as Datum>::components();
                            let gl_type =
                              <$field_type as Datum>::gl_type();
                            let normalized =
                                <$field_type as Datum>::normalized();
                            let stride = mem::size_of::<$name>();
                            let offset = offset_of!($name, $field_name);

                            gl.vertex_attrib_pointer(self.$field_name,
                                                     components,
                                                     gl_type,
                                                     normalized,
                                                     stride,
                                                     offset);
                        };)*
                    }
                }

                #[allow(dead_code)]
                pub struct BinderBuilder {
                    $($field_name: Option<$crate::ProgramAttrib>),*
                }

                #[allow(dead_code)]
                impl BinderBuilder {
                    pub fn new() -> Self {
                        BinderBuilder {
                            $($field_name: None),*
                        }
                    }

                    pub fn unwrap(self, gl: &$crate::Context) -> self::Binder {
                        let binder = self::Binder {
                            $($field_name: self.$field_name.expect(
                                concat!("No attribute provided for ",
                                        stringify!($field_name))
                            )),*
                        };

                        $(gl.enable_vertex_attrib_array(binder.$field_name);)*

                        binder
                    }

                    $(
                        pub fn $field_name(mut self,
                                           attrib: $crate::ProgramAttrib)
                        -> Self
                        {
                            self.$field_name = Some(attrib);
                            self
                        }
                    )*
                }
            })+
        }

        $(
            #[allow(unused_imports)]
            use self::_glitter_vertex_data::$name::$name;
        )+
    }
}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use futures::future::{self, Future};
use httparse;
use hyper::{Error, Method, StatusCode, Headers};
use hyper::header::{Origin, IfNoneMatch, ETag, EntityTag};
use hyper::server::{Request, Response};
use farmhash;

use super::header::ProxyHeader;
use super::tunnel::ProxyTunnel;
use header::janitor::HeaderJanitor;
use header::request_shard::HeaderRequestBloomRequestShard;
use header::status::{HeaderBloomStatus, HeaderBloomStatusValue};
use cache::read::CacheRead;
use cache::write::CacheWrite;
use cache::route::CacheRoute;
use LINE_FEED;

pub struct ProxyServe;

const CACHED_PARSE_MAX_HEADERS: usize = 100;

pub type ProxyServeFuture = Box<Future<Item = Response, Error = Error>>;

impl ProxyServe {
    pub fn handle(req: Request) -> ProxyServeFuture {
        info!("handled request: {} on {}", req.method(), req.path());

        if req.headers().has::<HeaderRequestBloomRequestShard>() == true {
            match *req.method() {
                Method::Options | Method::Head | Method::Get | Method::Post | Method::Patch |
                Method::Put | Method::Delete => Self::accept(req),
                _ => Self::reject(req, StatusCode::MethodNotAllowed),
            }
        } else {
            Self::reject(req, StatusCode::NotExtended)
        }
    }

    fn accept(req: Request) -> ProxyServeFuture {
        Self::tunnel(req)
    }

    fn reject(req: Request, status: StatusCode) -> ProxyServeFuture {
        let mut headers = Headers::new();

        headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Reject));

        Self::respond(&req.method(), status, headers, format!("{}", status))
    }

    fn tunnel(req: Request) -> ProxyServeFuture {
        let (method, uri, version, headers, body) = req.deconstruct();
        let (auth, shard) = ProxyHeader::parse_from_request(&headers);

        let ns = CacheRoute::gen_ns(
            shard,
            auth,
            version,
            &method,
            uri.path(),
            uri.query(),
            headers.get::<Origin>(),
        );

        info!("tunneling for ns = {}", ns);

        match CacheRead::acquire(ns.as_ref(), &method) {
            Ok(cached_value) => Self::dispatch_cached(&method, &headers, &cached_value),
            Err(_) => {
                // Clone method value for closures. Sadly, it looks like Rust borrow checker \
                //   doesnt discriminate properly on this check.
                let method_success = method.to_owned();
                let method_failure = method.to_owned();

                Box::new(
                    ProxyTunnel::run(&method, &uri, &headers, body, shard)
                        .and_then(move |tunnel_res| {
                            let res_status = tunnel_res.status();
                            let res_headers = tunnel_res.headers().to_owned();

                            CacheWrite::save(
                                ns,
                                method,
                                version,
                                res_status,
                                res_headers,
                                tunnel_res.body(),
                            )
                        })
                        .and_then(move |result| match result.body {
                            Ok(body_string) => {
                                Self::dispatch_fetched(
                                    &method_success,
                                    &result.status,
                                    result.headers,
                                    HeaderBloomStatusValue::Miss,
                                    body_string,
                                    result.value,
                                )
                            }
                            Err(body_string_values) => {
                                match body_string_values {
                                    Some(body_string) => {
                                        Self::dispatch_fetched(
                                            &method_success,
                                            &result.status,
                                            result.headers,
                                            HeaderBloomStatusValue::Direct,
                                            body_string,
                                            result.value,
                                        )
                                    }
                                    _ => Self::dispatch_failure(&method_success),
                                }
                            }
                        })
                        .or_else(move |_| Self::dispatch_failure(&method_failure)),
                )
            }
        }
    }

    fn dispatch_cached(method: &Method, headers: &Headers, res_string: &str) -> ProxyServeFuture {
        // Process ETag for cached content
        let (res_hash, res_etag) = Self::body_fingerprint(res_string);

        let isnt_modified = match headers.get::<IfNoneMatch>() {
            Some(req_if_none_match) => {
                (*req_if_none_match == IfNoneMatch::Items(vec![EntityTag::new(false, res_hash)]))
            }
            _ => false,
        };

        // Response not modified for client?
        if isnt_modified == true {
            // Process non-modified + cached headers
            let mut headers = Headers::new();

            headers.set::<ETag>(res_etag);
            headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Hit));

            // Serve non-modified response
            return Self::respond(method, StatusCode::NotModified, headers, String::from(""));
        }

        // Response modified
        let mut headers = [httparse::EMPTY_HEADER; CACHED_PARSE_MAX_HEADERS];
        let mut res = httparse::Response::new(&mut headers);

        // Split headers from body
        let mut res_body_string = String::new();
        let mut is_last_line_empty = false;

        for res_line in res_string.lines() {
            if res_body_string.is_empty() == false || is_last_line_empty == true {
                // Write to body
                res_body_string.push_str(res_line.as_ref());
                res_body_string.push_str(LINE_FEED);
            }

            is_last_line_empty = res_line.is_empty();
        }

        match res.parse(res_string.as_bytes()) {
            Ok(_) => {
                // Process cached status
                let code = res.code.unwrap_or(500u16);
                let status = StatusCode::try_from(code).unwrap_or(StatusCode::Unregistered(code));

                // Process cached headers
                let mut headers = Headers::new();

                for header in res.headers {
                    if let (Ok(header_name), Ok(header_value)) =
                        (
                            String::from_utf8(Vec::from(header.name)),
                            String::from_utf8(Vec::from(header.value)),
                        )
                    {
                        headers.set_raw(header_name, header_value);
                    }
                }

                headers.set::<ETag>(res_etag);
                headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Hit));

                // Serve cached response
                Self::respond(method, status, headers, res_body_string)
            }
            Err(err) => {
                error!("failed parsing cached response: {}", err);

                Self::dispatch_failure(method)
            }
        }
    }

    fn dispatch_fetched(
        method: &Method,
        status: &StatusCode,
        mut headers: Headers,
        bloom_status: HeaderBloomStatusValue,
        body_string: String,
        result_string: Option<String>,
    ) -> ProxyServeFuture {
        // Map headers to clean-up
        let mut headers_remove: Vec<String> = Vec::new();

        for header_view in headers.iter() {
            // Do not forward contextual and internal headers \
            //   (ie. 'Bloom-Response-*' headers)
            if HeaderJanitor::is_contextual(&header_view) == true ||
                HeaderJanitor::is_internal(&header_view) == true
            {
                headers_remove.push(String::from(header_view.name()));
            }
        }

        // Proceed headers clean-up
        for header_remove in headers_remove.iter() {
            headers.remove_raw(header_remove.as_ref());
        }

        // Process ETag for content?
        if let Some(result_string_value) = result_string {
            let (_, res_etag) = Self::body_fingerprint(&result_string_value);

            headers.set::<ETag>(res_etag);
        }

        headers.set(HeaderBloomStatus(bloom_status));

        Self::respond(method, *status, headers, body_string)
    }

    fn dispatch_failure(method: &Method) -> ProxyServeFuture {
        let status = StatusCode::BadGateway;

        let mut headers = Headers::new();

        headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Offline));

        Self::respond(method, status, headers, format!("{}", status))
    }

    fn body_fingerprint(body_string: &str) -> (String, ETag) {
        let body_hash = format!("{:x}", farmhash::fingerprint64(body_string.as_bytes()));
        let body_etag = ETag(EntityTag::new(false, body_hash.to_owned()));

        (body_hash, body_etag)
    }

    fn respond(
        method: &Method,
        status: StatusCode,
        headers: Headers,
        mut body_string: String,
    ) -> ProxyServeFuture {
        Box::new(future::ok(match method {
            &Method::Get | &Method::Post | &Method::Patch | &Method::Put => {
                // Ensure body string ends w/ a new line in any case, this \
                //   fixes an 'infinite loop' issue w/ Hyper
                if body_string.ends_with(LINE_FEED) == false {
                    body_string.push_str(LINE_FEED);
                }

                Response::new()
                    .with_status(status)
                    .with_headers(headers)
                    .with_body(body_string)
            }
            _ => Response::new().with_status(status).with_headers(headers),
        }))
    }
}
<commit_msg>Fix 304 Not Modified responses<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use futures::future::{self, Future};
use httparse;
use hyper::{Error, Method, StatusCode, Headers};
use hyper::header::{Origin, IfNoneMatch, ETag, EntityTag};
use hyper::server::{Request, Response};
use farmhash;

use super::header::ProxyHeader;
use super::tunnel::ProxyTunnel;
use header::janitor::HeaderJanitor;
use header::request_shard::HeaderRequestBloomRequestShard;
use header::status::{HeaderBloomStatus, HeaderBloomStatusValue};
use cache::read::CacheRead;
use cache::write::CacheWrite;
use cache::route::CacheRoute;
use LINE_FEED;

pub struct ProxyServe;

const CACHED_PARSE_MAX_HEADERS: usize = 100;

pub type ProxyServeFuture = Box<Future<Item = Response, Error = Error>>;

impl ProxyServe {
    pub fn handle(req: Request) -> ProxyServeFuture {
        info!("handled request: {} on {}", req.method(), req.path());

        if req.headers().has::<HeaderRequestBloomRequestShard>() == true {
            match *req.method() {
                Method::Options | Method::Head | Method::Get | Method::Post | Method::Patch |
                Method::Put | Method::Delete => Self::accept(req),
                _ => Self::reject(req, StatusCode::MethodNotAllowed),
            }
        } else {
            Self::reject(req, StatusCode::NotExtended)
        }
    }

    fn accept(req: Request) -> ProxyServeFuture {
        Self::tunnel(req)
    }

    fn reject(req: Request, status: StatusCode) -> ProxyServeFuture {
        let mut headers = Headers::new();

        headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Reject));

        Self::respond(&req.method(), status, headers, format!("{}", status))
    }

    fn tunnel(req: Request) -> ProxyServeFuture {
        let (method, uri, version, headers, body) = req.deconstruct();
        let (auth, shard) = ProxyHeader::parse_from_request(&headers);

        let ns = CacheRoute::gen_ns(
            shard,
            auth,
            version,
            &method,
            uri.path(),
            uri.query(),
            headers.get::<Origin>(),
        );

        info!("tunneling for ns = {}", ns);

        match CacheRead::acquire(ns.as_ref(), &method) {
            Ok(cached_value) => Self::dispatch_cached(&method, &headers, &cached_value),
            Err(_) => {
                // Clone method value for closures. Sadly, it looks like Rust borrow checker \
                //   doesnt discriminate properly on this check.
                let method_success = method.to_owned();
                let method_failure = method.to_owned();

                Box::new(
                    ProxyTunnel::run(&method, &uri, &headers, body, shard)
                        .and_then(move |tunnel_res| {
                            let res_status = tunnel_res.status();
                            let res_headers = tunnel_res.headers().to_owned();

                            CacheWrite::save(
                                ns,
                                method,
                                version,
                                res_status,
                                res_headers,
                                tunnel_res.body(),
                            )
                        })
                        .and_then(move |result| match result.body {
                            Ok(body_string) => {
                                Self::dispatch_fetched(
                                    &method_success,
                                    &result.status,
                                    result.headers,
                                    HeaderBloomStatusValue::Miss,
                                    body_string,
                                    result.value,
                                )
                            }
                            Err(body_string_values) => {
                                match body_string_values {
                                    Some(body_string) => {
                                        Self::dispatch_fetched(
                                            &method_success,
                                            &result.status,
                                            result.headers,
                                            HeaderBloomStatusValue::Direct,
                                            body_string,
                                            result.value,
                                        )
                                    }
                                    _ => Self::dispatch_failure(&method_success),
                                }
                            }
                        })
                        .or_else(move |_| Self::dispatch_failure(&method_failure)),
                )
            }
        }
    }

    fn dispatch_cached(method: &Method, headers: &Headers, res_string: &str) -> ProxyServeFuture {
        // Process ETag for cached content
        let (res_hash, res_etag) = Self::body_fingerprint(res_string);

        let isnt_modified = match headers.get::<IfNoneMatch>() {
            Some(req_if_none_match) => {
                (*req_if_none_match == IfNoneMatch::Items(vec![EntityTag::new(false, res_hash)]))
            }
            _ => false,
        };

        // Response not modified for client?
        if isnt_modified == true {
            // Process non-modified + cached headers
            let mut headers = Headers::new();

            headers.set::<ETag>(res_etag);
            headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Hit));

            // Serve non-modified response
            return Self::respond(method, StatusCode::NotModified, headers, String::from(""));
        }

        // Response modified
        let mut headers = [httparse::EMPTY_HEADER; CACHED_PARSE_MAX_HEADERS];
        let mut res = httparse::Response::new(&mut headers);

        // Split headers from body
        let mut res_body_string = String::new();
        let mut is_last_line_empty = false;

        for res_line in res_string.lines() {
            if res_body_string.is_empty() == false || is_last_line_empty == true {
                // Write to body
                res_body_string.push_str(res_line.as_ref());
                res_body_string.push_str(LINE_FEED);
            }

            is_last_line_empty = res_line.is_empty();
        }

        match res.parse(res_string.as_bytes()) {
            Ok(_) => {
                // Process cached status
                let code = res.code.unwrap_or(500u16);
                let status = StatusCode::try_from(code).unwrap_or(StatusCode::Unregistered(code));

                // Process cached headers
                let mut headers = Headers::new();

                for header in res.headers {
                    if let (Ok(header_name), Ok(header_value)) =
                        (
                            String::from_utf8(Vec::from(header.name)),
                            String::from_utf8(Vec::from(header.value)),
                        )
                    {
                        headers.set_raw(header_name, header_value);
                    }
                }

                headers.set::<ETag>(res_etag);
                headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Hit));

                // Serve cached response
                Self::respond(method, status, headers, res_body_string)
            }
            Err(err) => {
                error!("failed parsing cached response: {}", err);

                Self::dispatch_failure(method)
            }
        }
    }

    fn dispatch_fetched(
        method: &Method,
        status: &StatusCode,
        mut headers: Headers,
        bloom_status: HeaderBloomStatusValue,
        body_string: String,
        result_string: Option<String>,
    ) -> ProxyServeFuture {
        // Map headers to clean-up
        let mut headers_remove: Vec<String> = Vec::new();

        for header_view in headers.iter() {
            // Do not forward contextual and internal headers \
            //   (ie. 'Bloom-Response-*' headers)
            if HeaderJanitor::is_contextual(&header_view) == true ||
                HeaderJanitor::is_internal(&header_view) == true
            {
                headers_remove.push(String::from(header_view.name()));
            }
        }

        // Proceed headers clean-up
        for header_remove in headers_remove.iter() {
            headers.remove_raw(header_remove.as_ref());
        }

        // Process ETag for content?
        if let Some(result_string_value) = result_string {
            let (_, res_etag) = Self::body_fingerprint(&result_string_value);

            headers.set::<ETag>(res_etag);
        }

        headers.set(HeaderBloomStatus(bloom_status));

        Self::respond(method, *status, headers, body_string)
    }

    fn dispatch_failure(method: &Method) -> ProxyServeFuture {
        let status = StatusCode::BadGateway;

        let mut headers = Headers::new();

        headers.set::<HeaderBloomStatus>(HeaderBloomStatus(HeaderBloomStatusValue::Offline));

        Self::respond(method, status, headers, format!("{}", status))
    }

    fn body_fingerprint(body_string: &str) -> (String, ETag) {
        let body_hash = format!("{:x}", farmhash::fingerprint64(body_string.as_bytes()));
        let body_etag = ETag(EntityTag::new(false, body_hash.to_owned()));

        (body_hash, body_etag)
    }

    fn respond(
        method: &Method,
        status: StatusCode,
        headers: Headers,
        mut body_string: String,
    ) -> ProxyServeFuture {
        Box::new(future::ok(match method {
            &Method::Get | &Method::Post | &Method::Patch | &Method::Put => {
                Response::new()
                    .with_status(status)
                    .with_headers(headers)
                    .with_body(body_string)
            }
            _ => Response::new().with_status(status).with_headers(headers),
        }))
    }
}
<|endoftext|>


<commit_before>// DOCS

#![crate_name = "vobject"]
#![crate_type = "lib"]
#![license = "MIT"]
#![comment = "Parser for VObject and iCalendar."]

#![feature(phase)]
#[phase(plugin)]
extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};

pub struct Property {
    params: HashMap<String, String>,
    raw_value: String,
}

impl Property {
    fn new(params: HashMap<String, String>, raw_value: String) -> Property {
        Property {
            params: params,
            raw_value: raw_value
        }
    }

    #[doc="Get parameters."]
    pub fn get_params(&self) -> &HashMap<String, String> {
        &self.params
    }

    #[doc="Get value as unparsed string."]
    pub fn get_raw_value(&self) -> &String {
        &self.raw_value
    }

    #[doc="Get value as unescaped string."]
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.get_raw_value())
    }
}

pub struct Component {
    #[doc="The name of the component, such as `VCARD` or `VEVENT`."]
    pub name: String,

    #[doc="The component's properties."]
    pub props: HashMap<String, Vec<Property>>,

    #[doc="The component's child- or sub-components."]
    pub subcomponents: Vec<Component>
}

impl Component {
    fn new(name: String) -> Component {
        Component {
            name: name,
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    #[doc="Retrieve one property (from many) by key.
        Returns `None` if nothing is found."]
    pub fn single_prop(&self, key: &String) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    #[doc="Retrieve a mutable vector of properties for this key.
        Creates one (and inserts it into the component) if none exists."]
    pub fn all_props_mut(&mut self, key: String) -> &mut Vec<Property> {
        match self.props.entry(key) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.set(vec![])
        }
    }

    #[doc="Retrieve properties by key.
        Returns an empty slice if key doesn't exist."]
    pub fn all_props(&self, key: &String) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

#[pub]
component -> Component
    = name:component_begin
      ps:props
      cs:components?
      component_end {
        let mut rv = Component::new(name);

        match cs {
            Some(components) => { rv.subcomponents = components; },
            None => ()
        };

        for (k, v) in ps.into_iter() {
            rv.all_props_mut(k).push(v);
        };

        rv
    }

component_begin -> String
    = "BEGIN:" v:value __ { v }

component_end -> String
    = "END:" v:value __ { v }

components -> Vec<Component>
    = cs:component ++ eols __ { cs }

props -> Vec<(String, Property)>
    = ps:contentline ++ eols __ { ps }

contentline -> (String, Property)
    = k:name p:params ":" v:value {
        (k, Property::new(p, v))
    }

name -> String
    = !"BEGIN" !"END" iana_token+ { match_str.into_string() }

params -> HashMap<String, String>
    = ps:(";" p:param {p})* {
        let mut rv: HashMap<String, String> = HashMap::new();
        for (k, v) in ps.into_iter() {
            rv.insert(k, v);
        };
        rv
    }

param -> (String, String)
    // FIXME: Doesn't handle comma-separated values
    = k:param_name v:("=" v:param_value { v })? {
        (k, match v {
            Some(x) => x,
            None => "".into_string()
        })
    }

param_name -> String
    = iana_token+ { match_str.into_string() }

param_value -> String
    = x:(quoted_string / param_text) { x }

param_text -> String
    = safe_char* { match_str.into_string() }

value -> String
    = value_char+ { match_str.into_string() }

quoted_string -> String
    = dquote x:quoted_content dquote { x }

quoted_content -> String
    = qsafe_char* { match_str.into_string() }

iana_token = ([a-zA-Z0-9] / "-")+
safe_char = !";" !":" !"," value_char
qsafe_char = !dquote value_char // FIXME

value_char = !eol .

eol = "\n" / "\r\n" / "\r"
dquote = "\""
eols = eol+
whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

#[doc="Parse a component. The error value is a human-readable message."]
pub fn parse_component(s: &String) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = s
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\r ", "").replace("\r\t", "");

    parser::component(unfolded.as_slice())
}

#[doc="Escape text for a VObject property value."]
pub fn escape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

#[doc="Unescape text from a VObject property value."]
pub fn unescape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}
<commit_msg>nightly fixes<commit_after>// DOCS

#![crate_name = "vobject"]
#![crate_type = "lib"]
#![license = "MIT"]
#![comment = "Parser for VObject and iCalendar."]

#![feature(phase)]
#[phase(plugin)]
extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    params: HashMap<String, String>,
    raw_value: String,
}

impl Property {
    fn new(params: HashMap<String, String>, raw_value: String) -> Property {
        Property {
            params: params,
            raw_value: raw_value
        }
    }

    #[doc="Get parameters."]
    pub fn get_params(&self) -> &HashMap<String, String> {
        &self.params
    }

    #[doc="Get value as unparsed string."]
    pub fn get_raw_value(&self) -> &String {
        &self.raw_value
    }

    #[doc="Get value as unescaped string."]
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.get_raw_value())
    }
}

pub struct Component {
    #[doc="The name of the component, such as `VCARD` or `VEVENT`."]
    pub name: String,

    #[doc="The component's properties."]
    pub props: HashMap<String, Vec<Property>>,

    #[doc="The component's child- or sub-components."]
    pub subcomponents: Vec<Component>
}

impl Component {
    fn new(name: String) -> Component {
        Component {
            name: name,
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    #[doc="Retrieve one property (from many) by key.
        Returns `None` if nothing is found."]
    pub fn single_prop(&self, key: &String) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    #[doc="Retrieve a mutable vector of properties for this key.
        Creates one (and inserts it into the component) if none exists."]
    pub fn all_props_mut(&mut self, key: String) -> &mut Vec<Property> {
        match self.props.entry(key) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.set(vec![])
        }
    }

    #[doc="Retrieve properties by key.
        Returns an empty slice if key doesn't exist."]
    pub fn all_props(&self, key: &String) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

#[pub]
component -> Component
    = name:component_begin
      ps:props
      cs:components?
      component_end {
        let mut rv = Component::new(name);

        match cs {
            Some(components) => { rv.subcomponents = components; },
            None => ()
        };

        for (k, v) in ps.into_iter() {
            rv.all_props_mut(k).push(v);
        };

        rv
    }

component_begin -> String
    = "BEGIN:" v:value __ { v }

component_end -> String
    = "END:" v:value __ { v }

components -> Vec<Component>
    = cs:component ++ eols __ { cs }

props -> Vec<(String, Property)>
    = ps:contentline ++ eols __ { ps }

contentline -> (String, Property)
    = k:name p:params ":" v:value {
        (k, Property::new(p, v))
    }

name -> String
    = !"BEGIN" !"END" iana_token+ { match_str.into_string() }

params -> HashMap<String, String>
    = ps:(";" p:param {p})* {
        let mut rv: HashMap<String, String> = HashMap::new();
        for (k, v) in ps.into_iter() {
            rv.insert(k, v);
        };
        rv
    }

param -> (String, String)
    // FIXME: Doesn't handle comma-separated values
    = k:param_name v:("=" v:param_value { v })? {
        (k, match v {
            Some(x) => x,
            None => "".into_string()
        })
    }

param_name -> String
    = iana_token+ { match_str.into_string() }

param_value -> String
    = x:(quoted_string / param_text) { x }

param_text -> String
    = safe_char* { match_str.into_string() }

value -> String
    = value_char+ { match_str.into_string() }

quoted_string -> String
    = dquote x:quoted_content dquote { x }

quoted_content -> String
    = qsafe_char* { match_str.into_string() }

iana_token = ([a-zA-Z0-9] / "-")+
safe_char = !";" !":" !"," value_char
qsafe_char = !dquote value_char // FIXME

value_char = !eol .

eol = "\n" / "\r\n" / "\r"
dquote = "\""
eols = eol+
whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

#[doc="Parse a component. The error value is a human-readable message."]
pub fn parse_component(s: &String) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = s
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\r ", "").replace("\r\t", "");

    parser::component(unfolded.as_slice())
}

#[doc="Escape text for a VObject property value."]
pub fn escape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

#[doc="Unescape text from a VObject property value."]
pub fn unescape_chars(s: &String) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}
<|endoftext|>