<commit_before>use luminance::framebuffer::Framebuffer;
use luminance::pixel::{Depth32F, RGBA32F};
use luminance::tess::{Mode, Tess};
use luminance::texture::{Dim2, Flat, Texture, Unit};
use luminance::pipeline::Pipeline;
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::blending::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::{Program, Uniform};

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor),
  /// Simple fullscreen effect.
  ///
  /// Such a node is used to apply a user-defined shader on a fullscreen quad. The shader should
  /// provide both the vertex and fragment shader. The vertex shader doesn’t take any inputs but is
  /// invoked in an *attributeless* context on a triangle fan configuration. The fragment shader
  /// should output only one *RGBA* fragment.
  FullScreenEffect(&'a Program)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> From<&'a Program> for Node<'a> {
  fn from(program: &'a Program) -> Self {
    Node::FullScreenEffect(program)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];
      let screen = Framebuffer::default((self.w, self.h));
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(&screen, [0., 0., 0., 1.], &[&*fb.color_slot], &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render, &uniforms, &[], &[])
          });
        });
      });
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
      Node::FullScreenEffect(program) => self.fullscreen_effect(program)
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let texture_program = self.texture_program.borrow();
    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[&**texture], &[]).enter(|shd_gate| {
      shd_gate.new(&texture_program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          let uniforms = [TEXTURE_SOURCE.alter(Unit::new(0))];
          tess_gate.render(tess_render, &uniforms, &[], &[]);
        });
      });
    });

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[]).enter(|_| {});

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new((eq, src_fct, dst_fct), false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render.clone(), &uniforms, &[], &[]);

            let uniforms = [FORWARD_SOURCE.alter(Unit::new(1))];
            tess_gate.render(tess_render, &uniforms, &[], &[]);
          });
        });
      });
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }

  fn fullscreen_effect(&mut self, program: &Program) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[], &[]).enter(|shd_gate| {
      shd_gate.new(&program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(tess_render, &[], &[], &[]);
        });
      });
    });

    fb_index
  }
}
<commit_msg>Typo.<commit_after>use luminance::framebuffer::Framebuffer;
use luminance::pixel::{Depth32F, RGBA32F};
use luminance::tess::{Mode, Tess};
use luminance::texture::{Dim2, Flat, Texture, Unit};
use luminance::pipeline::Pipeline;
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::blending::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::{Program, Uniform};

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor),
  /// Simple fullscreen effect.
  ///
  /// Such a node is used to apply a user-defined shader on a fullscreen quad. The shader should
  /// provide both the vertex and fragment shader. The vertex shader doesn’t take any inputs but is
  /// invoked in an *attributeless* context on a triangle strip configuration. The fragment shader
  /// should output only one *RGBA* fragment.
  FullScreenEffect(&'a Program)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> From<&'a Program> for Node<'a> {
  fn from(program: &'a Program) -> Self {
    Node::FullScreenEffect(program)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];
      let screen = Framebuffer::default((self.w, self.h));
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(&screen, [0., 0., 0., 1.], &[&*fb.color_slot], &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render, &uniforms, &[], &[])
          });
        });
      });
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
      Node::FullScreenEffect(program) => self.fullscreen_effect(program)
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let texture_program = self.texture_program.borrow();
    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[&**texture], &[]).enter(|shd_gate| {
      shd_gate.new(&texture_program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          let uniforms = [TEXTURE_SOURCE.alter(Unit::new(0))];
          tess_gate.render(tess_render, &uniforms, &[], &[]);
        });
      });
    });

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[]).enter(|_| {});

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new((eq, src_fct, dst_fct), false, &[], &[], &[]).enter(|tess_gate| {
            let uniforms = [FORWARD_SOURCE.alter(Unit::new(0))];
            tess_gate.render(tess_render.clone(), &uniforms, &[], &[]);

            let uniforms = [FORWARD_SOURCE.alter(Unit::new(1))];
            tess_gate.render(tess_render, &uniforms, &[], &[]);
          });
        });
      });
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }

  fn fullscreen_effect(&mut self, program: &Program) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let tess_render = TessRender::from(&self.quad);

    Pipeline::new(fb, [0., 0., 0., 1.], &[], &[]).enter(|shd_gate| {
      shd_gate.new(&program, &[], &[], &[]).enter(|rdr_gate| {
        rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
          tess_gate.render(tess_render, &[], &[], &[]);
        });
      });
    });

    fb_index
  }
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
//! The module contains Rust representation of Cassandra consistency levels.
use std::io;
use std::convert::From;
use std::default::Default;
use super::{IntoBytes, FromCursor};
use super::types::*;
use super::FromBytes;

/// `Consistency` is an enum which represents Cassandra's consistency levels.
/// To find more details about each consistency level please refer to Cassandra official docs.
#[derive(Debug, PartialEq, Clone)]
pub enum Consistency {
    #[allow(missing_docs)]
    Any,
    #[allow(missing_docs)]
    One,
    #[allow(missing_docs)]
    Two,
    #[allow(missing_docs)]
    Three,
    #[allow(missing_docs)]
    Quorum,
    #[allow(missing_docs)]
    All,
    #[allow(missing_docs)]
    LocalQuorum,
    #[allow(missing_docs)]
    EachQuorum,
    #[allow(missing_docs)]
    Serial,
    #[allow(missing_docs)]
    LocalSerial,
    #[allow(missing_docs)]
    LocalOne,
}

impl Default for Consistency {
    fn default() -> Consistency {
        Consistency::One
    }
}

impl IntoBytes for Consistency {
    fn into_cbytes(&self) -> Vec<u8> {
        return match self {
            &Consistency::Any => to_short(0x0000),
            &Consistency::One => to_short(0x0001),
            &Consistency::Two => to_short(0x0002),
            &Consistency::Three => to_short(0x0003),
            &Consistency::Quorum => to_short(0x0004),
            &Consistency::All => to_short(0x0005),
            &Consistency::LocalQuorum => to_short(0x0006),
            &Consistency::EachQuorum => to_short(0x0007),
            &Consistency::Serial => to_short(0x0008),
            &Consistency::LocalSerial => to_short(0x0009),
            &Consistency::LocalOne => to_short(0x000A),
        };
    }
}

impl From<i32> for Consistency {
    fn from(bytes: i32) -> Consistency {
        return match bytes {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => unreachable!(),
        };
    }
}

impl FromBytes for Consistency {
    fn from_bytes(bytes: Vec<u8>) -> Consistency {
        return match from_bytes(bytes.clone()) {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => unreachable!(),
        };
    }
}

impl FromCursor for Consistency {
    fn from_cursor(mut cursor: &mut io::Cursor<Vec<u8>>) -> Consistency {
        let consistency_num = CIntShort::from_cursor(&mut cursor) as i32;
        return Consistency::from(consistency_num);
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use {IntoBytes, FromBytes, FromCursor};
    use super::*;

    #[test]
    fn test_consistency_into_cbytes() {
        assert_eq!(Consistency::Any.into_cbytes(), vec![0, 0]);
        assert_eq!(Consistency::One.into_cbytes(), vec![0, 1]);
        assert_eq!(Consistency::Two.into_cbytes(), vec![0, 2]);
        assert_eq!(Consistency::Three.into_cbytes(), vec![0, 3]);
        assert_eq!(Consistency::Quorum.into_cbytes(), vec![0, 4]);
        assert_eq!(Consistency::All.into_cbytes(), vec![0, 5]);
        assert_eq!(Consistency::LocalQuorum.into_cbytes(), vec![0, 6]);
        assert_eq!(Consistency::EachQuorum.into_cbytes(), vec![0, 7]);
        assert_eq!(Consistency::Serial.into_cbytes(), vec![0, 8]);
        assert_eq!(Consistency::LocalSerial.into_cbytes(), vec![0, 9]);
        assert_eq!(Consistency::LocalOne.into_cbytes(), vec![0, 10]);
    }

    #[test]
    fn test_consistency_from() {
        assert_eq!(Consistency::from(0), Consistency::Any);
        assert_eq!(Consistency::from(1), Consistency::One);
        assert_eq!(Consistency::from(2), Consistency::Two);
        assert_eq!(Consistency::from(3), Consistency::Three);
        assert_eq!(Consistency::from(4), Consistency::Quorum);
        assert_eq!(Consistency::from(5), Consistency::All);
        assert_eq!(Consistency::from(6), Consistency::LocalQuorum);
        assert_eq!(Consistency::from(7), Consistency::EachQuorum);
        assert_eq!(Consistency::from(8), Consistency::Serial);
        assert_eq!(Consistency::from(9), Consistency::LocalSerial);
        assert_eq!(Consistency::from(10), Consistency::LocalOne);
    }

    #[test]
    fn test_consistency_from_bytes() {
        assert_eq!(Consistency::from_bytes(vec![0, 0]), Consistency::Any);
        assert_eq!(Consistency::from_bytes(vec![0, 1]), Consistency::One);
        assert_eq!(Consistency::from_bytes(vec![0, 2]), Consistency::Two);
        assert_eq!(Consistency::from_bytes(vec![0, 3]), Consistency::Three);
        assert_eq!(Consistency::from_bytes(vec![0, 4]), Consistency::Quorum);
        assert_eq!(Consistency::from_bytes(vec![0, 5]), Consistency::All);
        assert_eq!(Consistency::from_bytes(vec![0, 6]),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 7]), Consistency::EachQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 8]), Consistency::Serial);
        assert_eq!(Consistency::from_bytes(vec![0, 9]),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_bytes(vec![0, 10]), Consistency::LocalOne);
    }

    #[test]
    fn test_consistency_from_cursor() {
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 0])),
                   Consistency::Any);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 1])),
                   Consistency::One);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 2])),
                   Consistency::Two);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 3])),
                   Consistency::Three);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 4])),
                   Consistency::Quorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 5])),
                   Consistency::All);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 6])),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 7])),
                   Consistency::EachQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 8])),
                   Consistency::Serial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 9])),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 10])),
                   Consistency::LocalOne);
    }

}
<commit_msg>added docs<commit_after>#![warn(missing_docs)]
//! The module contains Rust representation of Cassandra consistency levels.
use std::io;
use std::convert::From;
use std::default::Default;
use super::{IntoBytes, FromCursor};
use super::types::*;
use super::FromBytes;

/// `Consistency` is an enum which represents Cassandra's consistency levels.
/// To find more details about each consistency level please refer to Cassandra official docs.
#[derive(Debug, PartialEq, Clone)]
pub enum Consistency {
    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
    /// for that partition key.	Provides the highest consistency
    /// and the lowest availability of any other level.
    Any,
    ///
    /// A write must be written to the commit log and memtable of at least one replica node.
    /// Satisfies the needs of most users because consistency requirements are not stringent.
    One,
    /// A write must be written to the commit log and memtable of at least two replica nodes.
    /// Similar to ONE.
    Two,

    /// A write must be written to the commit log and memtable of at least three replica nodes.
    /// Similar to TWO.
    Three,
    /// A write must be written to the commit log and memtable on a quorum of replica nodes.
    /// Provides strong consistency if you can tolerate some level of failure.
    Quorum,
    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
    /// for that partition key.
    /// Provides the highest consistency and the lowest availability of any other level.
    All,
    /// Strong consistency. A write must be written to the commit log and memtable on a quorum
    /// of replica nodes in the same data center as thecoordinator node.
    /// Avoids latency of inter-data center communication.
    /// Used in multiple data center clusters with a rack-aware replica placement strategy,
    /// such as NetworkTopologyStrategy, and a properly configured snitch.
    /// Use to maintain consistency locally (within the single data center).
    /// Can be used with SimpleStrategy.
    LocalQuorum,
    /// Strong consistency. A write must be written to the commit log and memtable on a quorum of
    /// replica nodes in all data center.
    /// Used in multiple data center clusters to strictly maintain consistency at the same level
    /// in each data center. For example, choose this level
    /// if you want a read to fail when a data center is down and the QUORUM
    /// cannot be reached on that data center.
    EachQuorum,
    /// Achieves linearizable consistency for lightweight transactions by preventing unconditional
    /// updates.	You cannot configure this level as a normal consistency level,
    /// configured at the driver level using the consistency level field.
    /// You configure this level using the serial consistency field
    /// as part of the native protocol operation. See failure scenarios.
    Serial,
    /// Same as SERIAL but confined to the data center. A write must be written conditionally
    /// to the commit log and memtable on a quorum of replica nodes in the same data center.
    /// Same as SERIAL. Used for disaster recovery. See failure scenarios.
    LocalSerial,
    /// A write must be sent to, and successfully acknowledged by,
    /// at least one replica node in the local data center.
    /// In a multiple data center clusters, a consistency level of ONE is often desirable,
    /// but cross-DC traffic is not. LOCAL_ONE accomplishes this.
    /// For security and quality reasons, you can use this consistency level
    /// in an offline datacenter to prevent automatic connection
    /// to online nodes in other data centers if an offline node goes down.
    LocalOne,
    /// This is an error scenario either the client code doesn't support it or server is sending
    /// bad headers
    Unknown,
}

impl Default for Consistency {
    fn default() -> Consistency {
        Consistency::One
    }
}

impl IntoBytes for Consistency {
    fn into_cbytes(&self) -> Vec<u8> {
        return match self {
            &Consistency::Any => to_short(0x0000),
            &Consistency::One => to_short(0x0001),
            &Consistency::Two => to_short(0x0002),
            &Consistency::Three => to_short(0x0003),
            &Consistency::Quorum => to_short(0x0004),
            &Consistency::All => to_short(0x0005),
            &Consistency::LocalQuorum => to_short(0x0006),
            &Consistency::EachQuorum => to_short(0x0007),
            &Consistency::Serial => to_short(0x0008),
            &Consistency::LocalSerial => to_short(0x0009),
            &Consistency::LocalOne => to_short(0x000A),
            &Consistency::Unknown => to_short(0x0063),
            //giving Unknown a value of 99
        };
    }
}

impl From<i32> for Consistency {
    fn from(bytes: i32) -> Consistency {
        return match bytes {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => Consistency::Unknown,
        };
    }
}

impl FromBytes for Consistency {
    fn from_bytes(bytes: Vec<u8>) -> Consistency {
        return match from_bytes(bytes.clone()) {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => Consistency::Unknown,
        };
    }
}

impl FromCursor for Consistency {
    fn from_cursor(mut cursor: &mut io::Cursor<Vec<u8>>) -> Consistency {
        let consistency_num = CIntShort::from_cursor(&mut cursor) as i32;
        return Consistency::from(consistency_num);
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use {IntoBytes, FromBytes, FromCursor};
    use super::*;

    #[test]
    fn test_consistency_into_cbytes() {
        assert_eq!(Consistency::Any.into_cbytes(), vec![0, 0]);
        assert_eq!(Consistency::One.into_cbytes(), vec![0, 1]);
        assert_eq!(Consistency::Two.into_cbytes(), vec![0, 2]);
        assert_eq!(Consistency::Three.into_cbytes(), vec![0, 3]);
        assert_eq!(Consistency::Quorum.into_cbytes(), vec![0, 4]);
        assert_eq!(Consistency::All.into_cbytes(), vec![0, 5]);
        assert_eq!(Consistency::LocalQuorum.into_cbytes(), vec![0, 6]);
        assert_eq!(Consistency::EachQuorum.into_cbytes(), vec![0, 7]);
        assert_eq!(Consistency::Serial.into_cbytes(), vec![0, 8]);
        assert_eq!(Consistency::LocalSerial.into_cbytes(), vec![0, 9]);
        assert_eq!(Consistency::LocalOne.into_cbytes(), vec![0, 10]);
    }

    #[test]
    fn test_consistency_from() {
        assert_eq!(Consistency::from(0), Consistency::Any);
        assert_eq!(Consistency::from(1), Consistency::One);
        assert_eq!(Consistency::from(2), Consistency::Two);
        assert_eq!(Consistency::from(3), Consistency::Three);
        assert_eq!(Consistency::from(4), Consistency::Quorum);
        assert_eq!(Consistency::from(5), Consistency::All);
        assert_eq!(Consistency::from(6), Consistency::LocalQuorum);
        assert_eq!(Consistency::from(7), Consistency::EachQuorum);
        assert_eq!(Consistency::from(8), Consistency::Serial);
        assert_eq!(Consistency::from(9), Consistency::LocalSerial);
        assert_eq!(Consistency::from(10), Consistency::LocalOne);
        assert_eq!(Consistency::from(11), Consistency::Unknown);
    }

    #[test]
    fn test_consistency_from_bytes() {
        assert_eq!(Consistency::from_bytes(vec![0, 0]), Consistency::Any);
        assert_eq!(Consistency::from_bytes(vec![0, 1]), Consistency::One);
        assert_eq!(Consistency::from_bytes(vec![0, 2]), Consistency::Two);
        assert_eq!(Consistency::from_bytes(vec![0, 3]), Consistency::Three);
        assert_eq!(Consistency::from_bytes(vec![0, 4]), Consistency::Quorum);
        assert_eq!(Consistency::from_bytes(vec![0, 5]), Consistency::All);
        assert_eq!(Consistency::from_bytes(vec![0, 6]),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 7]), Consistency::EachQuorum);
        assert_eq!(Consistency::from_bytes(vec![0, 8]), Consistency::Serial);
        assert_eq!(Consistency::from_bytes(vec![0, 9]),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_bytes(vec![0, 10]), Consistency::LocalOne);
        assert_eq!(Consistency::from_bytes(vec![0, 11]), Consistency::Unknown);
    }

    #[test]
    fn test_consistency_from_cursor() {
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 0])),
                   Consistency::Any);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 1])),
                   Consistency::One);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 2])),
                   Consistency::Two);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 3])),
                   Consistency::Three);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 4])),
                   Consistency::Quorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 5])),
                   Consistency::All);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 6])),
                   Consistency::LocalQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 7])),
                   Consistency::EachQuorum);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 8])),
                   Consistency::Serial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 9])),
                   Consistency::LocalSerial);
        assert_eq!(Consistency::from_cursor(&mut Cursor::new(vec![0, 10])),
                   Consistency::LocalOne);
    }

}
<|endoftext|>


<commit_before>use graphics::{DrawState, Transformed, rectangle};
use graphics::polygon::Polygon;
use graphics::line::Line;
use opengl_graphics::GlGraphics;
use piston::input::Key;
use rand::Rng;
use std::f64::consts::PI;
use std::ops::{Sub, Mul, Div};

fn to_cartesian(theta: f64, r: f64) -> (f64, f64) {
    return (
        theta.sin()*r,
        -theta.cos()*r,
    )
}

#[derive(Copy, Clone)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn new(x: f64, y: f64) -> Self {
        Point {
            x: x,
            y: y,
        }
    }

    fn cross(self, other: Point) -> f64 {
        return self.x*other.y - other.x*self.y;
    }

    fn dot(self, other: Point) -> f64 {
        return self.x*other.x + self.y*other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self, other: Point) -> Self::Output {
        return Point{
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Div<f64> for Point {
    type Output = Point;

    fn div(self, other: f64) -> Self::Output {
        return Point{
            x: self.x / other,
            y: self.y / other,
        }
    }
}

// Intersection of p, p+r and q, q+s
// p + t r = q + u s
// t = ((q − p) × s) / (r × s)
// u = ((q − p) × r) / (r × s)

fn lines_intersect(l1: [f64; 4], l2: [f64; 4]) -> bool {
    let p = Point::new(l1[0], l1[1]);
    let q = Point::new(l2[0], l2[1]);
    let r = Point::new(l1[2] - l1[0], l1[3] - l1[1]);
    let s = Point::new(l2[2] - l2[0], l2[3] - l2[1]);

    //If r × s = 0 and (q − p) × r = 0, then the two lines are collinear.
    if (r.cross(s) == 0.0 && (p - q).cross(r) == 0.0) {
        // If the interval between t0 and t1 intersects the interval [0, 1] then the line segments are collinear and overlapping; otherwise they are collinear and disjoint.
        // Note that if s and r point in opposite directions, then s · r < 0 and so the interval to be checked is [t1, t0] rather than [t0, t1].
        //t0 = (q − p) · r / (r · r)
        //t1 = (q + s − p) · r / (r · r) = t0 + s · r / (r · r)
        let t0 = (q - p).dot(r / r.dot(r));
        let t1 = t0 + s.dot(r / r.dot(r));
        return !(t0 < 0.0 && t1 < 0.0 || t0 > 1.0 && t1 > 1.0)
    }

    // If r × s = 0 and (q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
    if (r.cross(s) == 0.0) {
        return false;
    }

    // t = (q − p) × s / (r × s)
    // u = (p − q) × r / (s × r)
    let t = (q - p).cross(s / (r.cross(s)));
    let u = (p - q).cross(r / (s.cross(r)));

    // If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s.
    return 0.0 <= t && t <= 1.0 && 0.0 <= u && u <= 1.0;
}

#[cfg(test)]
#[test]
fn test_lines_intersect() {
    let line = [-1.0, -1.0, 1.0, 1.0];
    // Two lines intersect normally
    assert!(lines_intersect(line, [1.0, -1.0, -1.0, 1.0]));
    // Two lines don't intersect at all
    assert!(!lines_intersect(line, [-2.0, -2.0, -3.0, -3.0]));
    // Two lines are parallel and don't intersect
    assert!(!lines_intersect(line, [-1.0, 0.0, 1.0, 2.0]));
    // Two lines are co-linear and overlapping
    assert!(lines_intersect(line, [-1.5, -1.5, 0.5, 0.5]));
    assert!(lines_intersect(line, [0.5, 0.5, 1.5, 1.5]));
    // Two lines are co-linear and one contains the other
    assert!(lines_intersect(line, [-2.0, -2.0, 2.0, 2.0]));
    assert!(lines_intersect(line, [-0.5, -0.5, 0.5, 0.5]));
    // Two lines are co-linear and non-overlapping
    assert!(!lines_intersect(line, [-3.0, -3.0, -2.0, -2.0]));
    assert!(!lines_intersect(line, [2.0, 2.0, 3.0, 3.0]));
    // Two lines are the same
    assert!(lines_intersect(line, line));
    // Two lines intersect at one point
    assert!(lines_intersect(line, [1.0, 1.0, 2.0, 2.0]));
    assert!(lines_intersect(line, [1.0, 1.0, 1.0, 2.0]));
    // One line's point touches the other line
    assert!(lines_intersect(line, [0.0, 2.0, 2.0, 0.0]));
}

pub struct Spaceship {
    x: f64,
    y: f64,
    v: f64,
    v_theta: f64,
    theta: f64,
    accel: f64,
    reverse: f64,
    left: f64,
    right: f64,
    firing: bool,
    cooldown: f64,
}

const SPACESHIP_POINTS: [[f64; 2]; 3] = [
    [5.0, 7.0],
    [-5.0, 7.0],
    [0.0, -13.0],
];

impl Spaceship {
    pub fn new() -> Spaceship {
        return Spaceship{
            x: 100.0,
            y: 100.0,
            v: 0.0,
            v_theta: 0.0,
            theta: 0.0,
            accel: 0.0,
            reverse: 0.0,
            left: 0.0,
            right: 0.0,
            firing: false,
            cooldown: 0.0,
        };
    }

    pub fn handle_press(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 1.0,
            Key::Down => self.reverse = 1.0,
            Key::Left => self.left = 0.05,
            Key::Right => self.right = 0.05,
            Key::Space => self.firing = true,
            _ => (),
        }
    }

    pub fn handle_release(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 0.0,
            Key::Down => self.reverse = 0.0,
            Key::Left => self.left = 0.0,
            Key::Right => self.right = 0.0,
            Key::Space => self.firing = false,
            _ => (),
        }
    }

    pub fn draw(&mut self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        Polygon::new(color).draw(
            &SPACESHIP_POINTS,
            ds,
            t
                .trans(self.x, self.y)
                .rot_rad(self.theta),
            gl,
        );
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let (dx, dy) = to_cartesian(self.v_theta, self.v*dt);
        self.x = (self.x + dx + x_max) % x_max;
        self.y = (self.y + dy + y_max) % y_max;
    }

    pub fn accelerate(&mut self, dt: f64) {
        let net_accel = (self.accel - self.reverse)*dt*100.0;
        let (dx, dy) = to_cartesian(self.v_theta, self.v);
        let (ddx, ddy) = to_cartesian(self.theta, net_accel);
        let new_dx = dx + ddx;
        let new_dy = dy + ddy;
        self.v = (new_dx*new_dx+new_dy*new_dy).sqrt().min(200.0).max(-200.0);
        self.v_theta = new_dx.atan2(-new_dy);
    }

    pub fn turn(&mut self, dt: f64) {
        self.theta += (self.right - self.left)*dt*100.0;
    }

    pub fn cooldown(&mut self, dt: f64) {
        self.cooldown = (self.cooldown - dt).max(0.0);
    }

    pub fn ready_to_fire(&self) -> bool {
        return self.cooldown == 0.0;
    }

    pub fn is_firing(&self) -> bool {
        return self.firing;
    }

    pub fn fire(&mut self, bullets: &mut Vec<Bullet>) {
        self.cooldown = 0.5;
        bullets.push(Bullet::new(self.x, self.y, self.theta));
    }
}

pub struct Bullet {
    x: f64,
    y: f64,
    theta: f64,
    distance: f64,
}

impl Bullet {
    fn new(x: f64, y: f64, theta: f64) -> Bullet {
        return Bullet{
            x: x,
            y: y,
            theta: theta,
            distance: 0.0,
        };
    }

    pub fn draw(&self, color: [f32; 4], t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        rectangle(color, rectangle::square(self.x, self.y, 2.0), t, gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let v = 100.0;
        self.x = (self.x + self.theta.sin()*v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*v*dt + y_max) % y_max;
        self.distance += v*dt;
    }

    pub fn is_alive(&self) -> bool {
        return self.distance < 100.0;
    }
}

pub struct Astroid {
    x: f64,
    y: f64,
    v: f64,
    theta: f64,
    border: Vec<[f64; 4]>,
}

impl Astroid {
    pub fn new<R: Rng>(rng: &mut R) -> Astroid {
        let radius = (rng.gen_range(1, 3)*5) as f64;
        return Astroid {
            x: rng.gen_range(0.0, 100.0),
            y: rng.gen_range(0.0, 100.0),
            v: rng.gen_range(40.0, 60.0),
            theta: rng.gen_range(0.0, 2.0*PI),
            border: Astroid::create_border(rng, radius),
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        let line_info = Line::new(color, 0.5);
        for line_points in self.border.iter() {
            line_info.draw(*line_points, ds, t.trans(self.x, self.y), gl);
        }
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.x = (self.x + self.theta.sin()*self.v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*self.v*dt + y_max) % y_max;
    }

    pub fn create_border<R: Rng>(rng: &mut R, radius: f64) -> Vec<[f64; 4]> {
        let spread = radius/5.0;
        let point_count = rng.gen_range(8, 12);
        let mut points = Vec::with_capacity(point_count);
        let theta_0 = rng.gen_range(0.0, 2.0*PI);
        for theta in (1..point_count+1).map(|i| theta_0 + 2.0*PI*i as f64/point_count as f64) {
            let distance = radius + rng.gen_range(-spread, spread);
            points.push(to_cartesian(theta, distance));
        };
        let point = points[0];
        points.push(point);
        let mut lines = Vec::with_capacity(point_count);
        for point in points.iter().zip(points.iter().skip(1)) {
            let (&(x1, x2), &(y1, y2)) = point;
            lines.push([x1, x2, y1, y2]);
        }
        return lines;
    }

    pub fn is_collision(&self, bullet_path: [f64; 4]) -> bool {
        return false;
    }
}<commit_msg>Added reference for the intersection algorithm<commit_after>use graphics::{DrawState, Transformed, rectangle};
use graphics::polygon::Polygon;
use graphics::line::Line;
use opengl_graphics::GlGraphics;
use piston::input::Key;
use rand::Rng;
use std::f64::consts::PI;
use std::ops::{Sub, Mul, Div};

fn to_cartesian(theta: f64, r: f64) -> (f64, f64) {
    return (
        theta.sin()*r,
        -theta.cos()*r,
    )
}

#[derive(Copy, Clone)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn new(x: f64, y: f64) -> Self {
        Point {
            x: x,
            y: y,
        }
    }

    fn cross(self, other: Point) -> f64 {
        return self.x*other.y - other.x*self.y;
    }

    fn dot(self, other: Point) -> f64 {
        return self.x*other.x + self.y*other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self, other: Point) -> Self::Output {
        return Point{
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Div<f64> for Point {
    type Output = Point;

    fn div(self, other: f64) -> Self::Output {
        return Point{
            x: self.x / other,
            y: self.y / other,
        }
    }
}

// Intersection of p, p+r and q, q+s
// For details, See: http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
// p + t r = q + u s
// t = ((q − p) × s) / (r × s)
// u = ((q − p) × r) / (r × s)

fn lines_intersect(l1: [f64; 4], l2: [f64; 4]) -> bool {
    let p = Point::new(l1[0], l1[1]);
    let q = Point::new(l2[0], l2[1]);
    let r = Point::new(l1[2] - l1[0], l1[3] - l1[1]);
    let s = Point::new(l2[2] - l2[0], l2[3] - l2[1]);

    //If r × s = 0 and (q − p) × r = 0, then the two lines are collinear.
    if (r.cross(s) == 0.0 && (p - q).cross(r) == 0.0) {
        // If the interval between t0 and t1 intersects the interval [0, 1] then the line segments are collinear and overlapping; otherwise they are collinear and disjoint.
        // Note that if s and r point in opposite directions, then s · r < 0 and so the interval to be checked is [t1, t0] rather than [t0, t1].
        //t0 = (q − p) · r / (r · r)
        //t1 = (q + s − p) · r / (r · r) = t0 + s · r / (r · r)
        let t0 = (q - p).dot(r / r.dot(r));
        let t1 = t0 + s.dot(r / r.dot(r));
        return !(t0 < 0.0 && t1 < 0.0 || t0 > 1.0 && t1 > 1.0)
    }

    // If r × s = 0 and (q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
    if (r.cross(s) == 0.0) {
        return false;
    }

    // t = (q − p) × s / (r × s)
    // u = (p − q) × r / (s × r)
    let t = (q - p).cross(s / (r.cross(s)));
    let u = (p - q).cross(r / (s.cross(r)));

    // If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s.
    return 0.0 <= t && t <= 1.0 && 0.0 <= u && u <= 1.0;
}

#[cfg(test)]
#[test]
fn test_lines_intersect() {
    let line = [-1.0, -1.0, 1.0, 1.0];
    // Two lines intersect normally
    assert!(lines_intersect(line, [1.0, -1.0, -1.0, 1.0]));
    // Two lines don't intersect at all
    assert!(!lines_intersect(line, [-2.0, -2.0, -3.0, -3.0]));
    // Two lines are parallel and don't intersect
    assert!(!lines_intersect(line, [-1.0, 0.0, 1.0, 2.0]));
    // Two lines are co-linear and overlapping
    assert!(lines_intersect(line, [-1.5, -1.5, 0.5, 0.5]));
    assert!(lines_intersect(line, [0.5, 0.5, 1.5, 1.5]));
    // Two lines are co-linear and one contains the other
    assert!(lines_intersect(line, [-2.0, -2.0, 2.0, 2.0]));
    assert!(lines_intersect(line, [-0.5, -0.5, 0.5, 0.5]));
    // Two lines are co-linear and non-overlapping
    assert!(!lines_intersect(line, [-3.0, -3.0, -2.0, -2.0]));
    assert!(!lines_intersect(line, [2.0, 2.0, 3.0, 3.0]));
    // Two lines are the same
    assert!(lines_intersect(line, line));
    // Two lines intersect at one point
    assert!(lines_intersect(line, [1.0, 1.0, 2.0, 2.0]));
    assert!(lines_intersect(line, [1.0, 1.0, 1.0, 2.0]));
    // One line's point touches the other line
    assert!(lines_intersect(line, [0.0, 2.0, 2.0, 0.0]));
}

pub struct Spaceship {
    x: f64,
    y: f64,
    v: f64,
    v_theta: f64,
    theta: f64,
    accel: f64,
    reverse: f64,
    left: f64,
    right: f64,
    firing: bool,
    cooldown: f64,
}

const SPACESHIP_POINTS: [[f64; 2]; 3] = [
    [5.0, 7.0],
    [-5.0, 7.0],
    [0.0, -13.0],
];

impl Spaceship {
    pub fn new() -> Spaceship {
        return Spaceship{
            x: 100.0,
            y: 100.0,
            v: 0.0,
            v_theta: 0.0,
            theta: 0.0,
            accel: 0.0,
            reverse: 0.0,
            left: 0.0,
            right: 0.0,
            firing: false,
            cooldown: 0.0,
        };
    }

    pub fn handle_press(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 1.0,
            Key::Down => self.reverse = 1.0,
            Key::Left => self.left = 0.05,
            Key::Right => self.right = 0.05,
            Key::Space => self.firing = true,
            _ => (),
        }
    }

    pub fn handle_release(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 0.0,
            Key::Down => self.reverse = 0.0,
            Key::Left => self.left = 0.0,
            Key::Right => self.right = 0.0,
            Key::Space => self.firing = false,
            _ => (),
        }
    }

    pub fn draw(&mut self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        Polygon::new(color).draw(
            &SPACESHIP_POINTS,
            ds,
            t
                .trans(self.x, self.y)
                .rot_rad(self.theta),
            gl,
        );
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let (dx, dy) = to_cartesian(self.v_theta, self.v*dt);
        self.x = (self.x + dx + x_max) % x_max;
        self.y = (self.y + dy + y_max) % y_max;
    }

    pub fn accelerate(&mut self, dt: f64) {
        let net_accel = (self.accel - self.reverse)*dt*100.0;
        let (dx, dy) = to_cartesian(self.v_theta, self.v);
        let (ddx, ddy) = to_cartesian(self.theta, net_accel);
        let new_dx = dx + ddx;
        let new_dy = dy + ddy;
        self.v = (new_dx*new_dx+new_dy*new_dy).sqrt().min(200.0).max(-200.0);
        self.v_theta = new_dx.atan2(-new_dy);
    }

    pub fn turn(&mut self, dt: f64) {
        self.theta += (self.right - self.left)*dt*100.0;
    }

    pub fn cooldown(&mut self, dt: f64) {
        self.cooldown = (self.cooldown - dt).max(0.0);
    }

    pub fn ready_to_fire(&self) -> bool {
        return self.cooldown == 0.0;
    }

    pub fn is_firing(&self) -> bool {
        return self.firing;
    }

    pub fn fire(&mut self, bullets: &mut Vec<Bullet>) {
        self.cooldown = 0.5;
        bullets.push(Bullet::new(self.x, self.y, self.theta));
    }
}

pub struct Bullet {
    x: f64,
    y: f64,
    theta: f64,
    distance: f64,
}

impl Bullet {
    fn new(x: f64, y: f64, theta: f64) -> Bullet {
        return Bullet{
            x: x,
            y: y,
            theta: theta,
            distance: 0.0,
        };
    }

    pub fn draw(&self, color: [f32; 4], t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        rectangle(color, rectangle::square(self.x, self.y, 2.0), t, gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let v = 100.0;
        self.x = (self.x + self.theta.sin()*v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*v*dt + y_max) % y_max;
        self.distance += v*dt;
    }

    pub fn is_alive(&self) -> bool {
        return self.distance < 100.0;
    }
}

pub struct Astroid {
    x: f64,
    y: f64,
    v: f64,
    theta: f64,
    border: Vec<[f64; 4]>,
}

impl Astroid {
    pub fn new<R: Rng>(rng: &mut R) -> Astroid {
        let radius = (rng.gen_range(1, 3)*5) as f64;
        return Astroid {
            x: rng.gen_range(0.0, 100.0),
            y: rng.gen_range(0.0, 100.0),
            v: rng.gen_range(40.0, 60.0),
            theta: rng.gen_range(0.0, 2.0*PI),
            border: Astroid::create_border(rng, radius),
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        let line_info = Line::new(color, 0.5);
        for line_points in self.border.iter() {
            line_info.draw(*line_points, ds, t.trans(self.x, self.y), gl);
        }
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.x = (self.x + self.theta.sin()*self.v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*self.v*dt + y_max) % y_max;
    }

    pub fn create_border<R: Rng>(rng: &mut R, radius: f64) -> Vec<[f64; 4]> {
        let spread = radius/5.0;
        let point_count = rng.gen_range(8, 12);
        let mut points = Vec::with_capacity(point_count);
        let theta_0 = rng.gen_range(0.0, 2.0*PI);
        for theta in (1..point_count+1).map(|i| theta_0 + 2.0*PI*i as f64/point_count as f64) {
            let distance = radius + rng.gen_range(-spread, spread);
            points.push(to_cartesian(theta, distance));
        };
        let point = points[0];
        points.push(point);
        let mut lines = Vec::with_capacity(point_count);
        for point in points.iter().zip(points.iter().skip(1)) {
            let (&(x1, x2), &(y1, y2)) = point;
            lines.push([x1, x2, y1, y2]);
        }
        return lines;
    }

    pub fn is_collision(&self, bullet_path: [f64; 4]) -> bool {
        return false;
    }
}<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Method {
    Trigram,
    Alphabet,
    Combined,
}

impl FromStr for Method {
    // TODO: implement normal error
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().trim() {
            "trigram" => Ok(Method::Trigram),
            "alphabet" => Ok(Method::Alphabet),
            "combined" => Ok(Method::Combined),
            _ => Err(format!("Cannot obtain Method from {:?}", s)),
        }
    }
}

impl fmt::Display for Method {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Method::Trigram => "Trigram",
            Method::Alphabet => "Alphabet",
            Method::Combined => "Combined",
        };
        write!(f, "{}", name)
    }
}

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

    #[test]
    fn test_from_str() {
        assert_eq!("trigram".parse::<Method>().unwrap(), Method::Trigram);
        assert_eq!("ALPHABET".parse::<Method>().unwrap(), Method::Alphabet);

        let result = "foobar".parse::<Method>();
        assert!(result.is_err());
    }
}
<commit_msg>impl Default for Method<commit_after>use std::fmt;
use std::str::FromStr;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Method {
    Trigram,
    Alphabet,
    Combined,
}

impl FromStr for Method {
    // TODO: implement normal error
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().trim() {
            "trigram" => Ok(Method::Trigram),
            "alphabet" => Ok(Method::Alphabet),
            "combined" => Ok(Method::Combined),
            _ => Err(format!("Cannot obtain Method from {:?}", s)),
        }
    }
}

impl fmt::Display for Method {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Method::Trigram => "Trigram",
            Method::Alphabet => "Alphabet",
            Method::Combined => "Combined",
        };
        write!(f, "{}", name)
    }
}

impl Default for Method {
    fn default() -> Self {
        Method::Combined
    }
}

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

    #[test]
    fn test_from_str() {
        assert_eq!("trigram".parse::<Method>().unwrap(), Method::Trigram);
        assert_eq!("ALPHABET".parse::<Method>().unwrap(), Method::Alphabet);

        let result = "foobar".parse::<Method>();
        assert!(result.is_err());
    }
}
<|endoftext|>


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

use hyper;
use serde;
use serde_json;

use BuildQuery;
use Groups;

pub const API_VERSION: u16 = 3;

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

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                client: {:?}, pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.client,
               self.pagination)
    }
}

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

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

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

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

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

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

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

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        let url = self.build_url(&query);
        info!("url: {:?}", url);
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body: {:?}", body);

        // FIXME: Properly handle the error. Will require defining our own errors...
        assert_eq!(res.status, hyper::status::StatusCode::Ok);

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

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

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<commit_msg>single_char_pattern<commit_after>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use BuildQuery;
use Groups;

pub const API_VERSION: u16 = 3;

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

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                client: {:?}, pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.client,
               self.pagination)
    }
}

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

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

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

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

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

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

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

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        let url = self.build_url(&query);
        info!("url: {:?}", url);
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body: {:?}", body);

        // FIXME: Properly handle the error. Will require defining our own errors...
        assert_eq!(res.status, hyper::status::StatusCode::Ok);

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

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

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<|endoftext|>


<commit_before>use futures::{Future, Poll, Stream};
use http_types;
use tokio_service::Service;

use client::{Connect, Client, FutureResponse};
use error::Error;
use http::Body;

/// A Client to make outgoing HTTP requests.
#[derive(Debug)]
pub struct CompatClient<C, B = Body> {
    inner: Client<C, B>
}

pub fn client<C, B>(client: Client<C, B>) -> CompatClient<C, B> {
    CompatClient { inner: client }
}

impl<C, B> Service for CompatClient<C, B>
where C: Connect,
      B: Stream<Error=Error> + 'static,
      B::Item: AsRef<[u8]>,
{
    type Request = http_types::Request<B>;
    type Response = http_types::Response<Body>;
    type Error = Error;
    type Future = CompatFutureResponse;

    fn call(&self, req: Self::Request) -> Self::Future {
        future(self.inner.call(req.into()))
    }
}

/// A `Future` that will resolve to an `http::Response`.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct CompatFutureResponse {
    inner: FutureResponse
}

pub fn future(fut: FutureResponse) -> CompatFutureResponse {
    CompatFutureResponse { inner: fut }
}

impl Future for CompatFutureResponse {
    type Item = http_types::Response<Body>;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Error> {
        self.inner.poll()
            .map(|a| a.map(|r| r.into()))
    }
}
<commit_msg>refactor(lib): fix compat layer after rename to proto<commit_after>use futures::{Future, Poll, Stream};
use http_types;
use tokio_service::Service;

use client::{Connect, Client, FutureResponse};
use error::Error;
use proto::Body;

/// A Client to make outgoing HTTP requests.
#[derive(Debug)]
pub struct CompatClient<C, B = Body> {
    inner: Client<C, B>
}

pub fn client<C, B>(client: Client<C, B>) -> CompatClient<C, B> {
    CompatClient { inner: client }
}

impl<C, B> Service for CompatClient<C, B>
where C: Connect,
      B: Stream<Error=Error> + 'static,
      B::Item: AsRef<[u8]>,
{
    type Request = http_types::Request<B>;
    type Response = http_types::Response<Body>;
    type Error = Error;
    type Future = CompatFutureResponse;

    fn call(&self, req: Self::Request) -> Self::Future {
        future(self.inner.call(req.into()))
    }
}

/// A `Future` that will resolve to an `http::Response`.
#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
pub struct CompatFutureResponse {
    inner: FutureResponse
}

pub fn future(fut: FutureResponse) -> CompatFutureResponse {
    CompatFutureResponse { inner: fut }
}

impl Future for CompatFutureResponse {
    type Item = http_types::Response<Body>;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Error> {
        self.inner.poll()
            .map(|a| a.map(|r| r.into()))
    }
}
<|endoftext|>


<commit_before>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

use std::fs::File;
use std::io::{BufReader, Read};
use std::mem;
use std::path::Path;
use std::ptr;

use libsodium_sys;
use rustc_serialize::hex::ToHex;

use error::Result;

const BUF_SIZE: usize = 1024;

/// Calculate the BLAKE2b hash of a file, return as a hex string
/// digest size = 32 BYTES
/// NOTE: the hashing is keyless
pub fn hash_file<P: AsRef<Path>>(filename: &P) -> Result<String> {
    let file = try!(File::open(filename.as_ref()));
    let mut reader = BufReader::new(file);
    hash_reader(&mut reader)
}

pub fn hash_reader(reader: &mut BufReader<File>) -> Result<String> {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; (unsafe { libsodium_sys::crypto_generichash_statebytes() })];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };

    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
    }

    let mut buf = [0u8; BUF_SIZE];
    loop {
        let bytes_read = try!(reader.read(&mut buf));
        if bytes_read == 0 {
            break;
        }
        let chunk = &buf[0..bytes_read];
        unsafe {
            libsodium_sys::crypto_generichash_update(pst, chunk.as_ptr(), chunk.len() as u64);
        }
    }
    unsafe {
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(out.to_hex())
}

#[cfg(test)]
mod test {
    use std::env;
    #[allow(unused_imports)]
    use std::fs::{self, File};
    #[allow(unused_imports)]
    use std::io;
    use std::path::PathBuf;

    #[cfg(feature = "functional")]
    use hyper::{header, Client, Url};
    use super::*;
    use super::super::test_support::*;

    #[allow(dead_code)]
    fn mk_local_tmpdir() -> PathBuf {
        let dir = env::current_exe()
                      .unwrap()
                      .parent()
                      .unwrap()
                      .parent()
                      .unwrap()
                      .parent()
                      .unwrap()
                      .parent()
                      .unwrap()
                      .parent()
                      .unwrap()
                      .join("tmp");
        fs::create_dir_all(&dir).unwrap();
        dir
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = hash_file(&fixture("signme.dat")).unwrap();
        let expected = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected = "e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected = "b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265";
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let url = "http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let dst: PathBuf = {
            let file = mk_local_tmpdir().join(url.rsplit('/').next().unwrap());
            if !file.is_file() {
                let client = match env::var("http_proxy") {
                    Ok(url) => {
                        let url = Url::parse(&url).unwrap();
                        Client::with_http_proxy(url.host_str().unwrap().to_string(),
                                                url.port_or_known_default().unwrap())
                    }
                    _ => Client::new(),
                };
                let mut response = client.get(url)
                                         .header(header::Connection::close())
                                         .send()
                                         .unwrap();
                let mut f = File::create(&file).unwrap();
                io::copy(&mut response, &mut f).unwrap();
            }
            file
        };
        let computed = hash_file(&dst).unwrap();
        let expected = "ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414";
        assert_eq!(computed, expected);
    }
}
<commit_msg>Switch from Mustache to Handlebars<commit_after>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

use std::fs::File;
use std::io::{BufReader, Read};
use std::mem;
use std::path::Path;
use std::ptr;

use libsodium_sys;
use rustc_serialize::hex::ToHex;

use error::Result;

const BUF_SIZE: usize = 1024;

/// Calculate the BLAKE2b hash of a file, return as a hex string
/// digest size = 32 BYTES
/// NOTE: the hashing is keyless
pub fn hash_file<P: AsRef<Path>>(filename: &P) -> Result<String> {
    let file = try!(File::open(filename.as_ref()));
    let mut reader = BufReader::new(file);
    hash_reader(&mut reader)
}

pub fn hash_string(data: &str) -> Result<String> {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; (unsafe { libsodium_sys::crypto_generichash_statebytes() })];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };
    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
        libsodium_sys::crypto_generichash_update(pst, data[..].as_ptr(), data.len() as u64);
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(out.to_hex())
}

pub fn hash_reader(reader: &mut BufReader<File>) -> Result<String> {
    let mut out = [0u8; libsodium_sys::crypto_generichash_BYTES];
    let mut st = vec![0u8; (unsafe { libsodium_sys::crypto_generichash_statebytes() })];
    let pst = unsafe {
        mem::transmute::<*mut u8, *mut libsodium_sys::crypto_generichash_state>(st.as_mut_ptr())
    };

    unsafe {
        libsodium_sys::crypto_generichash_init(pst, ptr::null_mut(), 0, out.len());
    }

    let mut buf = [0u8; BUF_SIZE];
    loop {
        let bytes_read = try!(reader.read(&mut buf));
        if bytes_read == 0 {
            break;
        }
        let chunk = &buf[0..bytes_read];
        unsafe {
            libsodium_sys::crypto_generichash_update(pst, chunk.as_ptr(), chunk.len() as u64);
        }
    }
    unsafe {
        libsodium_sys::crypto_generichash_final(pst, out.as_mut_ptr(), out.len());
    }
    Ok(out.to_hex())
}

#[cfg(test)]
mod test {
    use std::env;
    #[allow(unused_imports)]
    use std::fs::{self, File};
    #[allow(unused_imports)]
    use std::io;
    use std::path::PathBuf;

    #[cfg(feature = "functional")]
    use hyper::{header, Client, Url};
    use super::*;
    use super::super::test_support::*;

    #[allow(dead_code)]
    fn mk_local_tmpdir() -> PathBuf {
        let dir = env::current_exe()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("tmp");
        fs::create_dir_all(&dir).unwrap();
        dir
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = hash_file(&fixture("signme.dat")).unwrap();
        let expected = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected = "e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1";
        assert_eq!(computed, expected);

        let computed = hash_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected = "b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265";
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let url = "http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let dst: PathBuf = {
            let file = mk_local_tmpdir().join(url.rsplit('/').next().unwrap());
            if !file.is_file() {
                let client = match env::var("http_proxy") {
                    Ok(url) => {
                        let url = Url::parse(&url).unwrap();
                        Client::with_http_proxy(url.host_str().unwrap().to_string(),
                                                url.port_or_known_default().unwrap())
                    }
                    _ => Client::new(),
                };
                let mut response = client.get(url)
                    .header(header::Connection::close())
                    .send()
                    .unwrap();
                let mut f = File::create(&file).unwrap();
                io::copy(&mut response, &mut f).unwrap();
            }
            file
        };
        let computed = hash_file(&dst).unwrap();
        let expected = "ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414";
        assert_eq!(computed, expected);
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Arrays

#[cfg(not(test))]
fn main() {}

#[test]
fn create_array() {
	let empty_vec: Vec<int> = vec![];
	assert!(empty_vec.len() == 0);

	let prepopulated_vec = vec![1i, 2i, 3i];
	assert!(prepopulated_vec.len() == 3);

	// Three strings.
	let string_vec = vec!(
		"Foo".to_string(),
		"Bar".to_string(),
		"Baz".to_string()
	);
	assert!(string_vec.len() == 3);
}

#[test]
fn add_to_array() {
	// Mutatable adding.
	let mut a_vec: Vec<int> = vec![];
	a_vec.push(1i);
	assert!(a_vec == vec![1i]);

	// Immutable adding.
	let b_vec = vec![2i, 3i, 4i];
	let c_vec = a_vec.append(b_vec.as_slice());
	assert!(c_vec == vec![1i, 2i, 3i, 4i]);
}

#[test]
fn retrieving_from_array() {
	// Indexing.
	let a_vec = vec![1i, 2i, 3i];
	assert!(a_vec[0] == 1i);

	// A full copy of the vector, but mutable.
	let mut mut_vec = a_vec.clone();
	assert!(mut_vec.pop() == Some(3i));
	assert!(mut_vec == vec![1i, 2i]);
}
<commit_msg>arrays: style<commit_after>// Implements http://rosettacode.org/wiki/Arrays

#[cfg(not(test))]
fn main() {}

#[test]
fn create_array() {
	let empty_vec: Vec<int> = vec![];
	assert!(empty_vec.len() == 0);

	let prepopulated_vec = vec![1i, 2, 3];
	assert!(prepopulated_vec.len() == 3);

	// Three string slices.
	let string_vec = vec!["Foo", "Bar", "Baz"];
	assert!(string_vec.len() == 3);
}

#[test]
fn add_to_array() {
	// Mutatable adding.
	let mut a_vec = vec![];
	a_vec.push(1i);
	assert_eq!(a_vec[0], 1);

	// Immutable adding.
	let b_vec = vec![2, 3, 4];
	let c_vec = a_vec.append(b_vec.as_slice());
	assert_eq!(c_vec.as_slice(), &[1, 2, 3, 4]);
}

#[test]
fn retrieving_from_array() {
	// Indexing.
	let a_vec = vec![1i, 2, 3];
	assert!(a_vec[0] == 1i);

	// A full copy of the vector, but mutable.
	let mut mut_vec = a_vec.clone();
	assert_eq!(mut_vec.pop(), Some(3));
	assert_eq!(mut_vec.as_slice(), &[1, 2]);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::ipc;
use crate::ipc::IpcReceiver;
use crate::ipc::IpcReceiverSet;
use crate::ipc::IpcSelectionResult;
use crate::ipc::IpcSender;
use crate::ipc::OpaqueIpcMessage;
use crate::ipc::OpaqueIpcReceiver;
use futures::channel::mpsc::UnboundedReceiver;
use futures::channel::mpsc::UnboundedSender;
use futures::stream::FusedStream;
use futures::task::Context;
use futures::task::Poll;
use futures::Stream;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Mutex;
use std::thread;

/// A stream built from an IPC channel.
pub struct IpcStream<T>(UnboundedReceiver<OpaqueIpcMessage>, PhantomData<T>);

impl<T> Unpin for IpcStream<T> {}

// A router which routes from an IPC channel to a stream.
struct Router {
    // Send `(ipc_recv, send)` to this router to add a route
    // from the IPC receiver to the sender.
    add_route: UnboundedSender<(OpaqueIpcReceiver, UnboundedSender<OpaqueIpcMessage>)>,

    // Wake up the routing thread.
    wakeup: Mutex<IpcSender<()>>,
}

// Lazily initialize a singleton router,
// so we only end up with one routing thread per process.
lazy_static! {
    static ref ROUTER: Router = {
        let (send, mut recv) = futures::channel::mpsc::unbounded();
        let (waker, wakee) = ipc::channel().expect("Failed to create IPC channel");
        thread::spawn(move || {
            let mut receivers = IpcReceiverSet::new().expect("Failed to create receiver set");
            let mut senders = HashMap::<u64, UnboundedSender<OpaqueIpcMessage>>::new();
            let _ = receivers.add(wakee);
            while let Ok(mut selections) = receivers.select() {
                for selection in selections.drain(..) {
                    match selection {
                        IpcSelectionResult::MessageReceived(id, msg) =>
                            if let Some(sender) = senders.get(&id) {
                                let _ = sender.unbounded_send(msg);
                            },
                        IpcSelectionResult::ChannelClosed(id) => {
                            senders.remove(&id);
                        },
                    }
                }
                if !recv.is_terminated() {
                    while let Ok(Some((receiver, sender))) = recv.try_next() {
                        if let Ok(id) = receivers.add_opaque(receiver) {
                            senders.insert(id, sender);
                        }
                    }
                }
            }
        });
        Router {
            add_route: send,
            wakeup: Mutex::new(waker),
        }
    };
}

impl<T> IpcReceiver<T>
where
    T: for<'de> Deserialize<'de> + Serialize,
{
    /// Convert this IPC receiver into a stream.
    pub fn to_stream(self) -> IpcStream<T> {
        let opaque = self.to_opaque();
        let (send, recv) = futures::channel::mpsc::unbounded();
        let _ = ROUTER.add_route.unbounded_send((opaque, send));
        if let Ok(waker) = ROUTER.wakeup.lock() {
            let _ = waker.send(());
        }
        IpcStream(recv, PhantomData)
    }
}

impl<T> Stream for IpcStream<T>
where
    T: for<'de> Deserialize<'de> + Serialize,
{
    type Item = Result<T, bincode::Error>;

    fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<Self::Item>> {
        let recv = Pin::new(&mut self.0);
        match recv.poll_next(ctx) {
            Poll::Ready(Some(msg)) => Poll::Ready(Some(msg.to())),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}
<commit_msg>Auto merge of #288 - negator:patch-2, r=jdm<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::ipc;
use crate::ipc::IpcReceiver;
use crate::ipc::IpcReceiverSet;
use crate::ipc::IpcSelectionResult;
use crate::ipc::IpcSender;
use crate::ipc::OpaqueIpcMessage;
use crate::ipc::OpaqueIpcReceiver;
use futures::channel::mpsc::UnboundedReceiver;
use futures::channel::mpsc::UnboundedSender;
use futures::stream::FusedStream;
use futures::task::Context;
use futures::task::Poll;
use futures::Stream;
use serde::Deserialize;
use serde::Serialize;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::pin::Pin;
use std::sync::Mutex;
use std::thread;

/// A stream built from an IPC channel.
pub struct IpcStream<T>(UnboundedReceiver<OpaqueIpcMessage>, PhantomData<T>);

impl<T> Unpin for IpcStream<T> {}

// A router which routes from an IPC channel to a stream.
struct Router {
    // Send `(ipc_recv, send)` to this router to add a route
    // from the IPC receiver to the sender.
    add_route: UnboundedSender<(OpaqueIpcReceiver, UnboundedSender<OpaqueIpcMessage>)>,

    // Wake up the routing thread.
    wakeup: Mutex<IpcSender<()>>,
}

// Lazily initialize a singleton router,
// so we only end up with one routing thread per process.
lazy_static! {
    static ref ROUTER: Router = {
        let (send, mut recv) = futures::channel::mpsc::unbounded();
        let (waker, wakee) = ipc::channel().expect("Failed to create IPC channel");
        thread::spawn(move || {
            let mut receivers = IpcReceiverSet::new().expect("Failed to create receiver set");
            let mut senders = HashMap::<u64, UnboundedSender<OpaqueIpcMessage>>::new();
            let _ = receivers.add(wakee);
            while let Ok(mut selections) = receivers.select() {
                for selection in selections.drain(..) {
                    match selection {
                        IpcSelectionResult::MessageReceived(id, msg) =>
                            if let Some(sender) = senders.get(&id) {
                                let _ = sender.unbounded_send(msg);
                            },
                        IpcSelectionResult::ChannelClosed(id) => {
                            senders.remove(&id);
                        },
                    }
                }
                if !recv.is_terminated() {
                    while let Ok(Some((receiver, sender))) = recv.try_next() {
                        if let Ok(id) = receivers.add_opaque(receiver) {
                            senders.insert(id, sender);
                        }
                    }
                }
            }
        });
        Router {
            add_route: send,
            wakeup: Mutex::new(waker),
        }
    };
}

impl<T> IpcReceiver<T>
where
    T: for<'de> Deserialize<'de> + Serialize,
{
    /// Convert this IPC receiver into a stream.
    pub fn to_stream(self) -> IpcStream<T> {
        let opaque = self.to_opaque();
        let (send, recv) = futures::channel::mpsc::unbounded();
        let _ = ROUTER.add_route.unbounded_send((opaque, send));
        if let Ok(waker) = ROUTER.wakeup.lock() {
            let _ = waker.send(());
        }
        IpcStream(recv, PhantomData)
    }
}

impl<T> Stream for IpcStream<T>
where
    T: for<'de> Deserialize<'de> + Serialize,
{
    type Item = Result<T, bincode::Error>;

    fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Option<Self::Item>> {
        let recv = Pin::new(&mut self.0);
        match recv.poll_next(ctx) {
            Poll::Ready(Some(msg)) => Poll::Ready(Some(msg.to())),
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }
}

impl<T> FusedStream for IpcStream<T>
where
    T: for<'de> Deserialize<'de> + Serialize,
{
    fn is_terminated(&self) -> bool {
        self.0.is_terminated()
    }
}
<|endoftext|>