<commit_before>use luminance::{Dim2, Equation, Factor, Flat, Framebuffer, Mode, Pipe, Pipeline, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use std::cell::RefCell;

use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_window(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  center: Vert,
  radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_upper: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_upper: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_upper: left_upper
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

/// A renderer responsible of rendering shapes.
pub struct Renderer {
  framebuffer: Framebuffer<Flat, Dim2, Texture2D, ()>,
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  tri_vert_nb: RefCell<usize>,
  quads: RefCell<Tess>,
  quad_vert_nb: RefCell<usize>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  disc_vert_nb: RefCell<usize>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Renderer {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let fb = Framebuffer::new((w, h), 0).unwrap();

    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3), None);

    let quads = Tess::new(Mode::TriangleStrip, TessVertices::Reserve::<Vert>(max_quads * 4), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Renderer {
      framebuffer: fb,
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      tri_vert_nb: RefCell::new(0),
      quads: RefCell::new(quads),
      quad_vert_nb: RefCell::new(0),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      disc_vert_nb: RefCell::new(0),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  // Dispatch the supported shape.
  fn dispatch(&self, tris: &mut Tess, quads: &mut Tess, discs: &mut Tess, input: &RenderInput) {
    let mut tris = tris.as_slice_mut().unwrap();
    let mut tri_i = 0;
    let mut quads = quads.as_slice_mut().unwrap();
    let mut quad_i = 0;
    let mut discs = discs.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, d];

      for &v in &abcd {
        quads[quad_i] = v.to_clip_space(&self.unit_converter);
        quad_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    *self.tri_vert_nb.borrow_mut() = tri_i;
    *self.quad_vert_nb.borrow_mut() = quad_i;
    *self.disc_vert_nb.borrow_mut() = disc_i;
  }

  pub fn render(&self, input: RenderInput) -> &Texture2D {
    self.dispatch(&mut self.tris.borrow_mut(), &mut self.quads.borrow_mut(), &mut self.discs.borrow_mut(), &input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, *self.tri_vert_nb.borrow());
    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, *self.disc_vert_nb.borrow());
    let text_quad = TessRender::one_whole(&self.text_quad);

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_upper.pos),
        TEXT_SIZE.alter(self.unit_converter.from_window(tex_w as f32, tex_h as f32)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_upper.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_render_cmds: Vec<_> = input.texts.iter().enumerate().map(|(i, _)| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, vec![
            Pipe::new(text_quad.clone())
          ]))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    Pipeline::new(&self.framebuffer, [0., 0., 0., 0.], &[], &[], vec![
      // render triangles
      Pipe::new(ShadingCommand::new(&self.tri_program.borrow(), vec![
        Pipe::new(RenderCommand::new(None, true, vec![
          Pipe::new(tris)
        ]))
      ])),
      // render discs
      Pipe::empty()
        .uniforms(&disc_uniforms)
        .unwrap(ShadingCommand::new(&self.disc_program.borrow(), vec![
          Pipe::new(RenderCommand::new(None, true, vec![
            Pipe::new(discs)
          ]))
        ])),
      // render texts
      Pipe::new(ShadingCommand::new(&self.text_program.borrow(), text_render_cmds))
    ]).run();

    &self.framebuffer.color_slot
  }
}

#[derive(Clone)]
pub struct RenderInput<'a, 'b> where 'b: 'a {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'b>], f32)>
}

impl<'a, 'b> RenderInput<'a, 'b> where 'b: 'a {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'b>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);

    UnitConverter {
      rw: rw,
      twice_rw: rw * 0.5,
      twice_rh: h as f32 * 0.5
    }
  }

  /// Convert from *window space* coordinates.
  pub fn from_window(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    assert!(x_ >= -1. && x_ <= 1., "x={}", x_);

    let y_ = y * self.twice_rh - 1.;
    assert!(y_ >= -1. && y_ <= 1., "y={}", y_);

    [x_, y_]
  }
}
<commit_msg>Disk really fixed.<commit_after>use luminance::{Dim2, Equation, Factor, Flat, Framebuffer, Mode, Pipe, Pipeline, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use std::cell::RefCell;

use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects. Position coordinates are in *window space*.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }

  /// Convert the vertex’ position to *clip space*.
  ///
  /// > Note: the depth coordinate is not affected.
  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    let converted = converter.from_window(self.pos[0], self.pos[1]);
    let pos_ = [converted[0], converted[1], self.pos[2]];

    Vert {
      pos: pos_,
      color: self.color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Quad(pub Vert, pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  center: Vert,
  radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }

  fn to_clip_space(&self, converter: &UnitConverter) -> Self {
    Disc {
      center: self.center.to_clip_space(converter),
      radius: self.radius * converter.rw
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_upper: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_upper: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_upper: left_upper
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

/// A renderer responsible of rendering shapes.
pub struct Renderer {
  framebuffer: Framebuffer<Flat, Dim2, Texture2D, ()>,
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  tri_vert_nb: RefCell<usize>,
  quads: RefCell<Tess>,
  quad_vert_nb: RefCell<usize>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  disc_vert_nb: RefCell<usize>,
  text_program: Res<Program>,
  text_quad: Tess,
  unit_converter: UnitConverter,
}

impl Renderer {
  pub fn new(w: u32, h: u32, max_tris: usize, max_quads: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let fb = Framebuffer::new((w, h), 0).unwrap();

    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3), None);

    let quads = Tess::new(Mode::TriangleStrip, TessVertices::Reserve::<Vert>(max_quads * 4), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Renderer {
      framebuffer: fb,
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      tri_vert_nb: RefCell::new(0),
      quads: RefCell::new(quads),
      quad_vert_nb: RefCell::new(0),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      disc_vert_nb: RefCell::new(0),
      text_program: text_program,
      text_quad: text_quad,
      unit_converter: UnitConverter::new(w, h)
    }
  }

  // Dispatch the supported shape.
  fn dispatch(&self, tris: &mut Tess, quads: &mut Tess, discs: &mut Tess, input: &RenderInput) {
    let mut tris = tris.as_slice_mut().unwrap();
    let mut tri_i = 0;
    let mut quads = quads.as_slice_mut().unwrap();
    let mut quad_i = 0;
    let mut discs = discs.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      let abc = [a, b, c];

      for &v in &abc {
        tris[tri_i] = v.to_clip_space(&self.unit_converter);
        tri_i += 1;
      }
    }

    for &Quad(a, b, c, d) in input.quads {
      let abcd = [a, b, c, d];

      for &v in &abcd {
        quads[quad_i] = v.to_clip_space(&self.unit_converter);
        quad_i += 1;
      }
    }

    for disc in input.discs {
      discs[disc_i] = disc.to_clip_space(&self.unit_converter);
      disc_i += 1;
    }

    *self.tri_vert_nb.borrow_mut() = tri_i;
    *self.quad_vert_nb.borrow_mut() = quad_i;
    *self.disc_vert_nb.borrow_mut() = disc_i;
  }

  pub fn render(&self, input: RenderInput) -> &Texture2D {
    self.dispatch(&mut self.tris.borrow_mut(), &mut self.quads.borrow_mut(), &mut self.discs.borrow_mut(), &input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, *self.tri_vert_nb.borrow());
    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, *self.disc_vert_nb.borrow());
    let text_quad = TessRender::one_whole(&self.text_quad);

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_upper.pos),
        TEXT_SIZE.alter(self.unit_converter.from_window(tex_w as f32, tex_h as f32)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_upper.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_render_cmds: Vec<_> = input.texts.iter().enumerate().map(|(i, _)| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, vec![
            Pipe::new(text_quad.clone())
          ]))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    Pipeline::new(&self.framebuffer, [0., 0., 0., 0.], &[], &[], vec![
      // render triangles
      Pipe::new(ShadingCommand::new(&self.tri_program.borrow(), vec![
        Pipe::new(RenderCommand::new(None, true, vec![
          Pipe::new(tris)
        ]))
      ])),
      // render discs
      Pipe::empty()
        .uniforms(&disc_uniforms)
        .unwrap(ShadingCommand::new(&self.disc_program.borrow(), vec![
          Pipe::new(RenderCommand::new(None, true, vec![
            Pipe::new(discs)
          ]))
        ])),
      // render texts
      Pipe::new(ShadingCommand::new(&self.text_program.borrow(), text_render_cmds))
    ]).run();

    &self.framebuffer.color_slot
  }
}

#[derive(Clone)]
pub struct RenderInput<'a, 'b> where 'b: 'a {
  triangles: &'a [Triangle],
  quads: &'a [Quad],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'b>], f32)>
}

impl<'a, 'b> RenderInput<'a, 'b> where 'b: 'a {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      quads: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles,
      ..self
    }
  }

  pub fn quads(self, quads: &'a [Quad]) -> Self {
    RenderInput {
      quads: quads,
      ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'b>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// A *unit converter* is used to position stuff in overlay in a universal and screen independent
/// way.
///
/// The idea is that you provide should handle *window space* coordinates only. This type will then
/// help compute normalized coordinates the renderer can understand.
///
/// For the record, *window space* coordinates are defined as below – given a viewport size of
/// *w × h*:
///
/// ^ y = h
/// |
/// |
/// |    x = w
/// O------>
///
/// The formula used to convert from *window space* to what we call *clip space* is:
///
/// > x' = 2x / w - 1
/// > y' = 2y / h - 1
#[derive(Copy, Clone, Debug, PartialEq)]
struct UnitConverter {
  rw: f32,
  twice_rw: f32,
  twice_rh: f32
}

impl UnitConverter {
  /// Build a unit converter by giving it the size of the viewport.
  pub fn new(w: u32, h: u32) -> Self {
    let rw = 1. / (w as f32);

    UnitConverter {
      rw: rw,
      twice_rw: 2. * rw,
      twice_rh: 2. / (h as f32)
    }
  }

  /// Convert from *window space* coordinates.
  pub fn from_window(&self, x: f32, y: f32) -> [f32; 2] {
    let x_ = x * self.twice_rw - 1.;
    assert!(x_ >= -1. && x_ <= 1., "x={}", x_);

    let y_ = y * self.twice_rh - 1.;
    assert!(y_ >= -1. && y_ <= 1., "y={}", y_);

    [x_, y_]
  }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::mem;
use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};

use libc::{read, write, eventfd, dup, c_void};

use {Result, errno_result};

/// A safe wrapper around a Linux eventfd (man 2 eventfd).
///
/// An eventfd is useful because it is sendable across processes and can be used for signaling in
/// and out of the KVM API. They can also be polled like any other file descriptor.
pub struct EventFd {
    eventfd: File,
}

impl EventFd {
    /// Creates a new blocking EventFd with an initial value of 0.
    pub fn new() -> Result<EventFd> {
        // This is safe because eventfd merely allocated an eventfd for our process and we handle
        // the error case.
        let ret = unsafe { eventfd(0, 0) };
        if ret < 0 {
            return errno_result();
        }
        // This is safe because we checked ret for success and know the kernel gave us an fd that we
        // own.
        Ok(EventFd { eventfd: unsafe { File::from_raw_fd(ret) } })
    }

    /// Adds `v` to the eventfd's count, blocking until this won't overflow the count.
    pub fn write(&self, v: u64) -> Result<()> {
        // This is safe because we made this fd and the pointer we pass can not overflow because we
        // give the syscall's size parameter properly.
        let ret = unsafe {
            write(self.as_raw_fd(),
                  &v as *const u64 as *const c_void,
                  mem::size_of::<u64>())
        };
        if ret <= 0 {
            return errno_result();
        }
        Ok(())
    }

    /// Blocks until the the eventfd's count is non-zero, then resets the count to zero.
    pub fn read(&self) -> Result<u64> {
        let mut buf: u64 = 0;
        let ret = unsafe {
            // This is safe because we made this fd and the pointer we pass can not overflow because
            // we give the syscall's size parameter properly.
            read(self.as_raw_fd(),
                 &mut buf as *mut u64 as *mut c_void,
                 mem::size_of::<u64>())
        };
        if ret <= 0 {
            return errno_result();
        }
        Ok(buf)
    }

    /// Clones this EventFd, internally creating a new file descriptor. The new EventFd will share
    /// the same underlying count within the kernel.
    pub fn try_clone(&self) -> Result<EventFd> {
        // This is safe because we made this fd and properly check that it returns without error.
        let ret = unsafe { dup(self.as_raw_fd()) };
        if ret < 0 {
            return errno_result();
        }
        // This is safe because we checked ret for success and know the kernel gave us an fd that we
        // own.
        Ok(EventFd { eventfd: unsafe { File::from_raw_fd(ret) } })
    }
}

impl AsRawFd for EventFd {
    fn as_raw_fd(&self) -> RawFd {
        self.eventfd.as_raw_fd()
    }
}

unsafe impl ::Pollable for EventFd {
    fn pollable_fd(&self) -> RawFd {
        self.eventfd.as_raw_fd()
    }
}

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

    #[test]
    fn new() {
        EventFd::new().unwrap();
    }

    #[test]
    fn read_write() {
        let evt = EventFd::new().unwrap();
        evt.write(55).unwrap();
        assert_eq!(evt.read(), Ok(55));
    }

    #[test]
    fn clone() {
        let evt = EventFd::new().unwrap();
        let evt_clone = evt.try_clone().unwrap();
        evt.write(923).unwrap();
        assert_eq!(evt_clone.read(), Ok(923));
    }
}
<commit_msg>sys_util: implement FromRawFd for EventFd<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::mem;
use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};

use libc::{read, write, eventfd, dup, c_void};

use {Result, errno_result};

/// A safe wrapper around a Linux eventfd (man 2 eventfd).
///
/// An eventfd is useful because it is sendable across processes and can be used for signaling in
/// and out of the KVM API. They can also be polled like any other file descriptor.
pub struct EventFd {
    eventfd: File,
}

impl EventFd {
    /// Creates a new blocking EventFd with an initial value of 0.
    pub fn new() -> Result<EventFd> {
        // This is safe because eventfd merely allocated an eventfd for our process and we handle
        // the error case.
        let ret = unsafe { eventfd(0, 0) };
        if ret < 0 {
            return errno_result();
        }
        // This is safe because we checked ret for success and know the kernel gave us an fd that we
        // own.
        Ok(EventFd { eventfd: unsafe { File::from_raw_fd(ret) } })
    }

    /// Adds `v` to the eventfd's count, blocking until this won't overflow the count.
    pub fn write(&self, v: u64) -> Result<()> {
        // This is safe because we made this fd and the pointer we pass can not overflow because we
        // give the syscall's size parameter properly.
        let ret = unsafe {
            write(self.as_raw_fd(),
                  &v as *const u64 as *const c_void,
                  mem::size_of::<u64>())
        };
        if ret <= 0 {
            return errno_result();
        }
        Ok(())
    }

    /// Blocks until the the eventfd's count is non-zero, then resets the count to zero.
    pub fn read(&self) -> Result<u64> {
        let mut buf: u64 = 0;
        let ret = unsafe {
            // This is safe because we made this fd and the pointer we pass can not overflow because
            // we give the syscall's size parameter properly.
            read(self.as_raw_fd(),
                 &mut buf as *mut u64 as *mut c_void,
                 mem::size_of::<u64>())
        };
        if ret <= 0 {
            return errno_result();
        }
        Ok(buf)
    }

    /// Clones this EventFd, internally creating a new file descriptor. The new EventFd will share
    /// the same underlying count within the kernel.
    pub fn try_clone(&self) -> Result<EventFd> {
        // This is safe because we made this fd and properly check that it returns without error.
        let ret = unsafe { dup(self.as_raw_fd()) };
        if ret < 0 {
            return errno_result();
        }
        // This is safe because we checked ret for success and know the kernel gave us an fd that we
        // own.
        Ok(EventFd { eventfd: unsafe { File::from_raw_fd(ret) } })
    }
}

impl AsRawFd for EventFd {
    fn as_raw_fd(&self) -> RawFd {
        self.eventfd.as_raw_fd()
    }
}

impl FromRawFd for EventFd {
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
        EventFd {
            eventfd: File::from_raw_fd(fd)
        }
    }
}

unsafe impl ::Pollable for EventFd {
    fn pollable_fd(&self) -> RawFd {
        self.eventfd.as_raw_fd()
    }
}

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

    #[test]
    fn new() {
        EventFd::new().unwrap();
    }

    #[test]
    fn read_write() {
        let evt = EventFd::new().unwrap();
        evt.write(55).unwrap();
        assert_eq!(evt.read(), Ok(55));
    }

    #[test]
    fn clone() {
        let evt = EventFd::new().unwrap();
        let evt_clone = evt.try_clone().unwrap();
        evt.write(923).unwrap();
        assert_eq!(evt_clone.read(), Ok(923));
    }
}
<|endoftext|>


<commit_before>use byteorder::ReadBytesExt;
use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
#[cfg(feature = "unix_socket")]
use unix_socket::UnixStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawHandle, RawHandle};

use {SslMode, ConnectError, ConnectParams, ConnectTarget};
use io::{NegotiateSsl, StreamWrapper};
use message::{self, WriteMessage};
use message::FrontendMessage::SslRequest;

const DEFAULT_PORT: u16 = 5432;

/// A connection to the Postgres server.
///
/// It implements `Read`, `Write` and `StreamWrapper`, as well as `AsRawFd` on
/// Unix platforms and `AsRawHandle` on Windows platforms.
pub struct Stream(InternalStream);

impl Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for Stream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl StreamWrapper for Stream {
    fn get_ref(&self) -> &Stream {
        self
    }

    fn get_mut(&mut self) -> &mut Stream {
        self
    }
}

#[cfg(unix)]
impl AsRawFd for Stream {
    fn as_raw_fd(&self) -> RawFd {
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_fd(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => s.as_raw_fd(),
        }
    }
}

#[cfg(windows)]
impl AsRawHandle for Stream {
    fn as_raw_handle(&self) -> RawHandle {
        // Unix sockets aren't supported on windows, so no need to match
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_handle(),
        }
    }
}

enum InternalStream {
    Tcp(TcpStream),
    #[cfg(feature = "unix_socket")]
    Unix(UnixStream),
}

impl Read for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Write for InternalStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) => {
            Ok(try!(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)))
        }
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(ref path) => {
            let mut path = path.clone();
            path.push(&format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream<N>(params: &ConnectParams, ssl: &mut SslMode<N>)
                            -> Result<Box<StreamWrapper>, ConnectError>
        where N: NegotiateSsl {
    let mut socket = Stream(try!(open_socket(params)));

    let (ssl_required, negotiator) = match *ssl {
        SslMode::None => return Ok(Box::new(socket)),
        SslMode::Prefer(ref mut negotiator) => (false, negotiator),
        SslMode::Require(ref mut negotiator) => (true, negotiator),
    };

    try!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == 'N' as u8 {
        if ssl_required {
            return Err(ConnectError::NoSslSupport);
        } else {
            return Ok(Box::new(socket));
        }
    }

    // Postgres doesn't support SSL over unix sockets
    let host = match params.target {
        ConnectTarget::Tcp(ref host) => host,
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(_) => return Err(ConnectError::BadResponse)
    };

    match negotiator.negotiate_ssl(host, socket) {
        Ok(stream) => Ok(stream),
        Err(err) => Err(ConnectError::SslError(err))
    }
}
<commit_msg>AsRawSocket, not AsRawHandle<commit_after>use byteorder::ReadBytesExt;
use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
#[cfg(feature = "unix_socket")]
use unix_socket::UnixStream;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, RawSocket};

use {SslMode, ConnectError, ConnectParams, ConnectTarget};
use io::{NegotiateSsl, StreamWrapper};
use message::{self, WriteMessage};
use message::FrontendMessage::SslRequest;

const DEFAULT_PORT: u16 = 5432;

/// A connection to the Postgres server.
///
/// It implements `Read`, `Write` and `StreamWrapper`, as well as `AsRawFd` on
/// Unix platforms and `AsRawSocket` on Windows platforms.
pub struct Stream(InternalStream);

impl Read for Stream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl Write for Stream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

impl StreamWrapper for Stream {
    fn get_ref(&self) -> &Stream {
        self
    }

    fn get_mut(&mut self) -> &mut Stream {
        self
    }
}

#[cfg(unix)]
impl AsRawFd for Stream {
    fn as_raw_fd(&self) -> RawFd {
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_fd(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref s) => s.as_raw_fd(),
        }
    }
}

#[cfg(windows)]
impl AsRawSocket for Stream {
    fn as_raw_socket(&self) -> RawSocket {
        // Unix sockets aren't supported on windows, so no need to match
        match self.0 {
            InternalStream::Tcp(ref s) => s.as_raw_socket(),
        }
    }
}

enum InternalStream {
    Tcp(TcpStream),
    #[cfg(feature = "unix_socket")]
    Unix(UnixStream),
}

impl Read for InternalStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.read(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.read(buf),
        }
    }
}

impl Write for InternalStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.write(buf),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            InternalStream::Tcp(ref mut s) => s.flush(),
            #[cfg(feature = "unix_socket")]
            InternalStream::Unix(ref mut s) => s.flush(),
        }
    }
}

fn open_socket(params: &ConnectParams) -> Result<InternalStream, ConnectError> {
    let port = params.port.unwrap_or(DEFAULT_PORT);
    match params.target {
        ConnectTarget::Tcp(ref host) => {
            Ok(try!(TcpStream::connect(&(&**host, port)).map(InternalStream::Tcp)))
        }
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(ref path) => {
            let mut path = path.clone();
            path.push(&format!(".s.PGSQL.{}", port));
            Ok(try!(UnixStream::connect(&path).map(InternalStream::Unix)))
        }
    }
}

pub fn initialize_stream<N>(params: &ConnectParams, ssl: &mut SslMode<N>)
                            -> Result<Box<StreamWrapper>, ConnectError>
        where N: NegotiateSsl {
    let mut socket = Stream(try!(open_socket(params)));

    let (ssl_required, negotiator) = match *ssl {
        SslMode::None => return Ok(Box::new(socket)),
        SslMode::Prefer(ref mut negotiator) => (false, negotiator),
        SslMode::Require(ref mut negotiator) => (true, negotiator),
    };

    try!(socket.write_message(&SslRequest { code: message::SSL_CODE }));
    try!(socket.flush());

    if try!(socket.read_u8()) == 'N' as u8 {
        if ssl_required {
            return Err(ConnectError::NoSslSupport);
        } else {
            return Ok(Box::new(socket));
        }
    }

    // Postgres doesn't support SSL over unix sockets
    let host = match params.target {
        ConnectTarget::Tcp(ref host) => host,
        #[cfg(feature = "unix_socket")]
        ConnectTarget::Unix(_) => return Err(ConnectError::BadResponse)
    };

    match negotiator.negotiate_ssl(host, socket) {
        Ok(stream) => Ok(stream),
        Err(err) => Err(ConnectError::SslError(err))
    }
}
<|endoftext|>


<commit_before>use std::cmp::{Ordering, PartialOrd, Ord};
use std::collections::{BTreeMap, btree_map};
use std::ops::Deref;
use std::str::FromStr;

use rustc_serialize::{Decoder, Decodable};

pub type Path = Option<String>;

#[derive(Debug, PartialEq, Eq)]
pub struct RoutingTable<H>(BTreeMap<Host, BTreeMap<Path, H>>);

#[derive(Debug, PartialEq, Eq)]
pub struct Host(String);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Match<'a> {
    Word(&'a str),
    Asterisk,
}

impl<T: Decodable> Decodable for RoutingTable<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_map(|mut d, n| {
            let mut rv = BTreeMap::new();
            for idx in 0..n {
                let (host, path) = d.read_map_elt_key(idx, |mut d| {
                    d.read_str().map(parse_host_path)
                })?;
                let val = d.read_map_elt_val(idx, T::decode)?;
                rv.entry(host)
                .or_insert_with(|| BTreeMap::new())
                .insert(path, val);
            }
            Ok(RoutingTable(rv))
        })
    }
}

impl<T> RoutingTable<T> {
    pub fn hosts(&self) -> btree_map::Iter<Host, BTreeMap<Path, T>> {
        self.0.iter()
    }
    #[allow(dead_code)]
    pub fn num_hosts(&self) -> usize {
        self.0.len()
    }
}

impl<'a> Match<'a> {
    fn new(val: &'a str) -> Match<'a> {
        if val == "*" {
            Match::Asterisk
        } else {
            Match::Word(val)
        }
    }
}

impl Ord for Host {
    fn cmp(&self, other: &Host) -> Ordering {
        let a = self.0.split('.').rev().map(Match::new);
        let b = other.0.split('.').rev().map(Match::new);
        a.cmp(b)
    }
}

impl PartialOrd for Host {
    fn partial_cmp(&self, other: &Host) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Host {
    pub fn matches(&self, host: &str) -> bool {
        let h = self.0.as_str();
        if h.starts_with("*.") {
            host.ends_with(&h[1..])
        } else {
            host == h
        }
    }
}

impl FromStr for Host {
    type Err = ();

    fn from_str(val: &str) -> Result<Host, ()> {
        Ok(Host(val.to_string()))
    }
}

impl Deref for Host {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}

fn parse_host_path(val: String) -> (Host, Path) {
    let (host, path) = if let Some(i) = val.find('/') {
        if &val[i..] == "/" {
            (&val[..i], None)
        } else {
            (&val[..i], Some(val[i..].to_string()))
        }
    } else {
        (val.as_str(), None)
    };
    (host.parse().unwrap(), path)
}

/// Map host port to a route of arbitrary type
///
/// Returns destination route and relative path
pub fn route<'x, D>(host: &str, path: &'x str,
    table: &'x RoutingTable<D>)
    -> Option<(&'x D, &'x str, &'x str)>
{
    // TODO(tailhook) transform into range iteration when `btree_range` is
    // stable
    for (route_host, sub_table) in table.hosts() {
        if route_host.matches(host) {
            for (route_path, result) in sub_table.iter().rev() {
                if path_match(&route_path, path) {
                    // Longest match is the last in reversed iteration
                    let prefix = route_path.as_ref().map(|x| &x[..]).unwrap_or("");
                    return Some((result, prefix, &path[prefix.len()..]));
                }
            }
            return None;
        }
    }
    return None;
}

fn path_match<S: AsRef<str>>(pattern: &Option<S>, value: &str) -> bool {
    if let Some(ref prefix) = *pattern {
        let prefix = prefix.as_ref();
        if value.starts_with(prefix) && (
                value.len() == prefix.len() ||
                value[prefix.len()..].starts_with("/") ||
                value[prefix.len()..].starts_with("?"))
        {
            return true;
        }
        return false;
    } else {
        return true;
    }
}

/// Returns host with trimmed whitespace and without port number if exists
pub fn parse_host(host_header: &str) -> &str {
    match host_header.find(':') {
        Some(idx) => &host_header[..idx],
        None => host_header,
    }.trim()
}

#[cfg(test)]
mod route_test {
    use super::{Host, Path};
    use super::route;
    use super::RoutingTable;

    #[test]
    fn route_host() {
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/", &table),
                   Some((&1, "", "/")));
        assert_eq!(route("example.org", "/hello", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
    }

    #[test]
    fn route_host_suffix() {
        // Routing table
        //   example.com: 1
        //   *.example.com: 2
        //   *.example.com/static: 3
        //   www.example.com/static/favicon.ico: 4
        //   xxx.example.com: 5
        //   *.aaa.example.com: 6
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*.example.com".parse().unwrap(), vec![
                (None, 2),
                (Some("/static".into()), 3),
                ].into_iter().collect()),
            ("www.example.com".parse().unwrap(), vec![
                (Some("/static/favicon.ico".into()), 4),
                ].into_iter().collect()),
            ("xxx.example.com".parse().unwrap(), vec![
                (None, 5),
                ].into_iter().collect()),
            ("*.aaa.example.com".parse().unwrap(), vec![
                (None, 6),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("www.example.com", "/", &table), None);
        assert_eq!(route("www.example.com", "/static/i", &table), None);
        assert_eq!(route("www.example.com", "/static/favicon.ico", &table),
                   Some((&4, "/static/favicon.ico", "")));
        assert_eq!(route("xxx.example.com", "/hello", &table),
                   Some((&5, "", "/hello")));
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("xxx.aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("city.example.com", "/static", &table),
                   Some((&3, "/static", "")));
    }
    /*
    #[test]
    fn route_path() {
        let table = vec![
            (Route { host: "ex.com".into(), path: Some("/one".into()) }, 1),
            (Route { host: "ex.com".into(), path: None }, 0),
            (Route { host: "ex.com".into(), path: Some("/two".into()) }, 2),
            ].into_iter().collect();
        assert_eq!(route("ex.com", "/one", &table),
                   Some((&1, "")));
        assert_eq!(route("ex.com", "/one/end", &table),
                   Some((&1, "/end")));
        assert_eq!(route("ex.com", "/two", &table),
                   Some((&2, "")));
        assert_eq!(route("ex.com","/two/some", &table),
                   Some((&2, "/some")));
        assert_eq!(route("ex.com", "/three", &table),
                   Some((&0, "/three")));
        assert_eq!(route("ex.com", "/", &table),
                   Some((&0, "/")));
        assert_eq!(route("ex.org", "/one", &table), None);
        assert_eq!(route("subdomain.ex.org", "/two", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.org", "/two", &table), None);
    }
    */

}

#[cfg(test)]
mod parse_test {
    use super::{Host, Path};
    use super::parse_host_path;

    #[test]
    fn simple() {
        let s = "example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn base_host() {
        let s = "*.example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_base_host() {
        let s = "*example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*example.com".into()));
        assert!(path.is_none());

        let s = ".example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host(".example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_host() {
        // FiXME: only dot is invalid
        let s = "*.".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());

        let s = "*./".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());
    }

    #[test]
    fn match_host() {
        let h = Host("example.com".into());
        assert!(h.matches("example.com"));
        assert!(!h.matches(".example.com"));
        assert!(!h.matches("www.example.com"));

        let h = Host("*.example.com".into());
        assert!(!h.matches("example.com"));
        assert!(h.matches("xxx.example.com"));
        assert!(h.matches("www.example.com"));
    }

    #[test]
    fn ordering() {
        let mut ordered: Vec<Host> = vec![
            "aaa".parse().unwrap(),
            "*.bbb".parse().unwrap(),
            "*.aaa.bbb".parse().unwrap(),
            "*.zzz.bbb".parse().unwrap(),
            "aaa.zzz".parse().unwrap(),
        ];
        ordered.sort();
        assert_eq!(ordered, [
            Host("aaa".into()),
            Host("*.aaa.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.bbb".into()),
            Host("aaa.zzz".into()),
        ]);
        ordered.reverse();
        assert_eq!(ordered, [
            Host("aaa.zzz".into()),
            Host("*.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.aaa.bbb".into()),
            Host("aaa".into()),
        ]);
    }

}
<commit_msg>Uncommented path routing test<commit_after>use std::cmp::{Ordering, PartialOrd, Ord};
use std::collections::{BTreeMap, btree_map};
use std::ops::Deref;
use std::str::FromStr;

use rustc_serialize::{Decoder, Decodable};

pub type Path = Option<String>;

#[derive(Debug, PartialEq, Eq)]
pub struct RoutingTable<H>(BTreeMap<Host, BTreeMap<Path, H>>);

#[derive(Debug, PartialEq, Eq)]
pub struct Host(String);

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
enum Match<'a> {
    Word(&'a str),
    Asterisk,
}

impl<T: Decodable> Decodable for RoutingTable<T> {
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        d.read_map(|mut d, n| {
            let mut rv = BTreeMap::new();
            for idx in 0..n {
                let (host, path) = d.read_map_elt_key(idx, |mut d| {
                    d.read_str().map(parse_host_path)
                })?;
                let val = d.read_map_elt_val(idx, T::decode)?;
                rv.entry(host)
                .or_insert_with(|| BTreeMap::new())
                .insert(path, val);
            }
            Ok(RoutingTable(rv))
        })
    }
}

impl<T> RoutingTable<T> {
    pub fn hosts(&self) -> btree_map::Iter<Host, BTreeMap<Path, T>> {
        self.0.iter()
    }
    #[allow(dead_code)]
    pub fn num_hosts(&self) -> usize {
        self.0.len()
    }
}

impl<'a> Match<'a> {
    fn new(val: &'a str) -> Match<'a> {
        if val == "*" {
            Match::Asterisk
        } else {
            Match::Word(val)
        }
    }
}

impl Ord for Host {
    fn cmp(&self, other: &Host) -> Ordering {
        let a = self.0.split('.').rev().map(Match::new);
        let b = other.0.split('.').rev().map(Match::new);
        a.cmp(b)
    }
}

impl PartialOrd for Host {
    fn partial_cmp(&self, other: &Host) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Host {
    pub fn matches(&self, host: &str) -> bool {
        let h = self.0.as_str();
        if h.starts_with("*.") {
            host.ends_with(&h[1..])
        } else {
            host == h
        }
    }
}

impl FromStr for Host {
    type Err = ();

    fn from_str(val: &str) -> Result<Host, ()> {
        Ok(Host(val.to_string()))
    }
}

impl Deref for Host {
    type Target = String;

    fn deref(&self) -> &String {
        &self.0
    }
}

fn parse_host_path(val: String) -> (Host, Path) {
    let (host, path) = if let Some(i) = val.find('/') {
        if &val[i..] == "/" {
            (&val[..i], None)
        } else {
            (&val[..i], Some(val[i..].to_string()))
        }
    } else {
        (val.as_str(), None)
    };
    (host.parse().unwrap(), path)
}

/// Map host port to a route of arbitrary type
///
/// Returns destination route and relative path
pub fn route<'x, D>(host: &str, path: &'x str,
    table: &'x RoutingTable<D>)
    -> Option<(&'x D, &'x str, &'x str)>
{
    // TODO(tailhook) transform into range iteration when `btree_range` is
    // stable
    for (route_host, sub_table) in table.hosts() {
        if route_host.matches(host) {
            for (route_path, result) in sub_table.iter().rev() {
                if path_match(&route_path, path) {
                    // Longest match is the last in reversed iteration
                    let prefix = route_path.as_ref().map(|x| &x[..]).unwrap_or("");
                    return Some((result, prefix, &path[prefix.len()..]));
                }
            }
            return None;
        }
    }
    return None;
}

fn path_match<S: AsRef<str>>(pattern: &Option<S>, value: &str) -> bool {
    if let Some(ref prefix) = *pattern {
        let prefix = prefix.as_ref();
        if value.starts_with(prefix) && (
                value.len() == prefix.len() ||
                value[prefix.len()..].starts_with("/") ||
                value[prefix.len()..].starts_with("?"))
        {
            return true;
        }
        return false;
    } else {
        return true;
    }
}

/// Returns host with trimmed whitespace and without port number if exists
pub fn parse_host(host_header: &str) -> &str {
    match host_header.find(':') {
        Some(idx) => &host_header[..idx],
        None => host_header,
    }.trim()
}

#[cfg(test)]
mod route_test {
    use super::{Host, Path};
    use super::route;
    use super::RoutingTable;

    #[test]
    fn route_host() {
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("example.com", "/", &table),
                   Some((&1, "", "/")));
        assert_eq!(route("example.org", "/hello", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
    }

    #[test]
    fn route_host_suffix() {
        // Routing table
        //   example.com: 1
        //   *.example.com: 2
        //   *.example.com/static: 3
        //   www.example.com/static/favicon.ico: 4
        //   xxx.example.com: 5
        //   *.aaa.example.com: 6
        let table = RoutingTable(vec![
            ("example.com".parse().unwrap(), vec![
                (None, 1),
                ].into_iter().collect()),
            ("*.example.com".parse().unwrap(), vec![
                (None, 2),
                (Some("/static".into()), 3),
                ].into_iter().collect()),
            ("www.example.com".parse().unwrap(), vec![
                (Some("/static/favicon.ico".into()), 4),
                ].into_iter().collect()),
            ("xxx.example.com".parse().unwrap(), vec![
                (None, 5),
                ].into_iter().collect()),
            ("*.aaa.example.com".parse().unwrap(), vec![
                (None, 6),
                ].into_iter().collect()),
            ].into_iter().collect());

        assert_eq!(route("test.example.com", "/hello", &table),
                   Some((&2, "", "/hello")));
        assert_eq!(route("www.example.com", "/", &table), None);
        assert_eq!(route("www.example.com", "/static/i", &table), None);
        assert_eq!(route("www.example.com", "/static/favicon.ico", &table),
                   Some((&4, "/static/favicon.ico", "")));
        assert_eq!(route("xxx.example.com", "/hello", &table),
                   Some((&5, "", "/hello")));
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.com", "/hello", &table),
                   Some((&1, "", "/hello")));
        assert_eq!(route("xxx.aaa.example.com", "/hello", &table),
                   Some((&6, "", "/hello")));
        assert_eq!(route("city.example.com", "/static", &table),
                   Some((&3, "/static", "")));
    }

    #[test]
    fn route_path() {
        let table = RoutingTable(vec![
            ("ex.com".parse().unwrap(), vec![
                (None , 0),
                (Some("/one".into()), 1),
                (Some("/two".into()) , 2),
                ].into_iter().collect()),
            ].into_iter().collect());
        assert_eq!(route("ex.com", "/one", &table),
                   Some((&1, "/one", "")));
        assert_eq!(route("ex.com", "/one/end", &table),
                   Some((&1, "/one", "/end")));
        assert_eq!(route("ex.com", "/two", &table),
                   Some((&2, "/two", "")));
        assert_eq!(route("ex.com","/two/some", &table),
                   Some((&2, "/two", "/some")));
        assert_eq!(route("ex.com", "/three", &table),
                   Some((&0, "", "/three")));
        assert_eq!(route("ex.com", "/", &table),
                   Some((&0, "", "/")));
        assert_eq!(route("ex.org", "/one", &table), None);
        assert_eq!(route("subdomain.ex.org", "/two", &table), None);
        assert_eq!(route("example.org", "/", &table), None);
        assert_eq!(route("example.org", "/two", &table), None);
    }

}

#[cfg(test)]
mod parse_test {
    use super::{Host, Path};
    use super::parse_host_path;

    #[test]
    fn simple() {
        let s = "example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn base_host() {
        let s = "*.example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_base_host() {
        let s = "*example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*example.com".into()));
        assert!(path.is_none());

        let s = ".example.com".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host(".example.com".into()));
        assert!(path.is_none());
    }

    #[test]
    fn invalid_host() {
        // FiXME: only dot is invalid
        let s = "*.".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());

        let s = "*./".to_string();
        let (host, path) = parse_host_path(s);
        assert_eq!(host, Host("*.".into()));
        assert!(path.is_none());
    }

    #[test]
    fn match_host() {
        let h = Host("example.com".into());
        assert!(h.matches("example.com"));
        assert!(!h.matches(".example.com"));
        assert!(!h.matches("www.example.com"));

        let h = Host("*.example.com".into());
        assert!(!h.matches("example.com"));
        assert!(h.matches("xxx.example.com"));
        assert!(h.matches("www.example.com"));
    }

    #[test]
    fn ordering() {
        let mut ordered: Vec<Host> = vec![
            "aaa".parse().unwrap(),
            "*.bbb".parse().unwrap(),
            "*.aaa.bbb".parse().unwrap(),
            "*.zzz.bbb".parse().unwrap(),
            "aaa.zzz".parse().unwrap(),
        ];
        ordered.sort();
        assert_eq!(ordered, [
            Host("aaa".into()),
            Host("*.aaa.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.bbb".into()),
            Host("aaa.zzz".into()),
        ]);
        ordered.reverse();
        assert_eq!(ordered, [
            Host("aaa.zzz".into()),
            Host("*.bbb".into()),
            Host("*.zzz.bbb".into()),
            Host("*.aaa.bbb".into()),
            Host("aaa".into()),
        ]);
    }

}
<|endoftext|>


<commit_before>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

extern crate native;
extern crate time;
extern crate zmq;

use std::comm;
use std::os;

fn server(mut pull_socket: zmq::Socket, mut push_socket: zmq::Socket, mut workers: uint) {
    let mut count = 0u;
    let mut msg = zmq::Message::new();

    while workers != 0 {
        match pull_socket.recv(&mut msg, 0) {
            Err(e) => fail!(e.to_str()),
            Ok(()) => {
                msg.with_str(|s| {
                    if s == "" {
                        workers -= 1;
                    } else {
                        count += from_str::<uint>(s).unwrap();
                    }
                })
            }
        }
    }

    match push_socket.send_str(count.to_str(), 0) {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }
}

fn spawn_server(ctx: &mut zmq::Context, workers: uint) -> comm::Chan<()> {
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    pull_socket.bind("inproc://server-pull").unwrap();
    push_socket.bind("inproc://server-push").unwrap();

    // Spawn the server.
    let (ready_po, ready_ch) = comm::Chan::new();
    let (start_po, start_ch) = comm::Chan::new();

    // Mutable sockets cannot be implicitly captured.
    let pull_socket = pull_socket;
    let push_socket = push_socket;

    native::task::spawn(proc() {
        // Let the main thread know we're ready.
        ready_ch.send(());

        // Wait until we need to start.
        start_po.recv();

        server(pull_socket, push_socket, workers);
    });

    // Wait for the server to start.
    ready_po.recv();

    start_ch
}

fn worker(mut push_socket: zmq::Socket, count: uint) {
    for _ in range(0, count) {
        push_socket.send_str(100u.to_str(), 0).unwrap();
    }

    // Let the server know we're done.
    push_socket.send_str("", 0).unwrap();
}

fn spawn_worker(ctx: &mut zmq::Context, count: uint) -> comm::Port<()> {
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();

    // Mutable sockets cannot be implicitly captured.
    let push_socket = push_socket;

    // Spawn the worker.
    let (po, ch) = comm::Chan::new();
    native::task::spawn(proc() {
        // Let the main thread we're ready.
        ch.send(());

        worker(push_socket, count);

        ch.send(());
    });

    // Wait for the worker to start.
    po.recv();

    po
}

fn run(ctx: &mut zmq::Context, size: uint, workers: uint) {
    let start_ch = spawn_server(ctx, workers);

    // Create some command/control sockets.
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    pull_socket.connect("inproc://server-push").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();
    //pull_socket.connect("tcp://127.0.0.1:3457").unwrap();

    // Spawn all the workers.
    let mut worker_results = ~[];
    for _ in range(0, workers) {
        worker_results.push(spawn_worker(ctx, size / workers));
    }

    let start = time::precise_time_s();

    start_ch.send(());

    // Block until all the workers finish.
    for po in worker_results.iter() {
        po.recv();
    }

    // Receive the final count.
    let result = match pull_socket.recv_msg(0) {
        Ok(msg) => msg.with_str(|s| from_str::<uint>(s).unwrap()),
        Err(e) => fail!(e.to_str()),
    };

    let end = time::precise_time_s();
    let elapsed = end - start;

    println!("Count is {}", result);
    println!("Test took {} seconds", elapsed);
    let thruput = ((size / workers * workers) as f64) / elapsed;
    println!("Throughput={:f} per sec", thruput);
}

fn main() {
    let args = os::args();

    let args = if os::getenv("RUST_BENCH").is_some() {
        ~[~"", ~"1000000", ~"10000"]
    } else if args.len() <= 1u {
        ~[~"", ~"10000", ~"4"]
    } else {
        args
    };

    let size = from_str::<uint>(args[1]).unwrap();
    let workers = from_str::<uint>(args[2]).unwrap();

    let mut ctx = zmq::Context::new();

    run(&mut ctx, size, workers);
}
<commit_msg>Update to use std::comm::channel.<commit_after>// A port of the simplistic benchmark from
//
//    http://github.com/PaulKeeble/ScalaVErlangAgents
//
// I *think* it's the same, more or less.

extern crate native;
extern crate time;
extern crate zmq;

use std::comm;
use std::os;

fn server(mut pull_socket: zmq::Socket, mut push_socket: zmq::Socket, mut workers: uint) {
    let mut count = 0u;
    let mut msg = zmq::Message::new();

    while workers != 0 {
        match pull_socket.recv(&mut msg, 0) {
            Err(e) => fail!(e.to_str()),
            Ok(()) => {
                msg.with_str(|s| {
                    if s == "" {
                        workers -= 1;
                    } else {
                        count += from_str::<uint>(s).unwrap();
                    }
                })
            }
        }
    }

    match push_socket.send_str(count.to_str(), 0) {
        Ok(()) => { }
        Err(e) => fail!(e.to_str()),
    }
}

fn spawn_server(ctx: &mut zmq::Context, workers: uint) -> comm::Sender<()> {
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    pull_socket.bind("inproc://server-pull").unwrap();
    push_socket.bind("inproc://server-push").unwrap();

    // Spawn the server.
    let (ready_tx, ready_rx) = comm::channel();
    let (start_tx, start_rx) = comm::channel();

    // Mutable sockets cannot be implicitly captured.
    let pull_socket = pull_socket;
    let push_socket = push_socket;

    native::task::spawn(proc() {
        // Let the main thread know we're ready.
        ready_tx.send(());

        // Wait until we need to start.
        start_rx.recv();

        server(pull_socket, push_socket, workers);
    });

    // Wait for the server to start.
    ready_rx.recv();

    start_tx
}

fn worker(mut push_socket: zmq::Socket, count: uint) {
    for _ in range(0, count) {
        push_socket.send_str(100u.to_str(), 0).unwrap();
    }

    // Let the server know we're done.
    push_socket.send_str("", 0).unwrap();
}

fn spawn_worker(ctx: &mut zmq::Context, count: uint) -> comm::Receiver<()> {
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();

    // Mutable sockets cannot be implicitly captured.
    let push_socket = push_socket;

    // Spawn the worker.
    let (tx, rx) = comm::channel();
    native::task::spawn(proc() {
        // Let the main thread we're ready.
        tx.send(());

        worker(push_socket, count);

        tx.send(());
    });

    // Wait for the worker to start.
    rx.recv();

    rx
}

fn run(ctx: &mut zmq::Context, size: uint, workers: uint) {
    let start_ch = spawn_server(ctx, workers);

    // Create some command/control sockets.
    let mut push_socket = ctx.socket(zmq::PUSH).unwrap();
    let mut pull_socket = ctx.socket(zmq::PULL).unwrap();

    push_socket.connect("inproc://server-pull").unwrap();
    pull_socket.connect("inproc://server-push").unwrap();
    //push_socket.connect("tcp://127.0.0.1:3456").unwrap();
    //pull_socket.connect("tcp://127.0.0.1:3457").unwrap();

    // Spawn all the workers.
    let mut worker_results = ~[];
    for _ in range(0, workers) {
        worker_results.push(spawn_worker(ctx, size / workers));
    }

    let start = time::precise_time_s();

    start_ch.send(());

    // Block until all the workers finish.
    for po in worker_results.iter() {
        po.recv();
    }

    // Receive the final count.
    let result = match pull_socket.recv_msg(0) {
        Ok(msg) => msg.with_str(|s| from_str::<uint>(s).unwrap()),
        Err(e) => fail!(e.to_str()),
    };

    let end = time::precise_time_s();
    let elapsed = end - start;

    println!("Count is {}", result);
    println!("Test took {} seconds", elapsed);
    let thruput = ((size / workers * workers) as f64) / elapsed;
    println!("Throughput={:f} per sec", thruput);
}

fn main() {
    let args = os::args();

    let args = if os::getenv("RUST_BENCH").is_some() {
        ~[~"", ~"1000000", ~"10000"]
    } else if args.len() <= 1u {
        ~[~"", ~"10000", ~"4"]
    } else {
        args
    };

    let size = from_str::<uint>(args[1]).unwrap();
    let workers = from_str::<uint>(args[2]).unwrap();

    let mut ctx = zmq::Context::new();

    run(&mut ctx, size, workers);
}
<|endoftext|>


<commit_before>use alloc::{Allocator, SliceWrapper};
use super::BrotliAlloc;
use super::backward_references::BrotliEncoderParams;
pub trait Joinable<T:Send+'static>:Sized {
  fn join(self) -> Result<T, ()>;
}

pub struct CompressionThreadResult<Alloc:BrotliAlloc+Send+'static> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  compressed: <Alloc as Allocator<u8>>::AllocatedMemory,
  compressed_size: usize,
  alloc: Alloc,
}
enum InternalSendAlloc<Alloc:BrotliAlloc+Send+'static, Join: Joinable<CompressionThreadResult<Alloc>>>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  A(Alloc),
  Join(Join),
  Spawning,
}
pub struct SendAlloc<Alloc:BrotliAlloc +Send+'static,
                     Join:Joinable<CompressionThreadResult<Alloc>>>(InternalSendAlloc<Alloc, Join>)
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send;

impl<Alloc:BrotliAlloc+Send+'static,Join:Joinable<CompressionThreadResult<Alloc>>> SendAlloc<Alloc, Join>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  pub fn new(alloc: Alloc) -> Self {
    SendAlloc::<Alloc, Join>(InternalSendAlloc::A(alloc))
  }
  pub fn unwrap_or(self, other: Alloc) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::Spawning | InternalSendAlloc::Join(_) => {
        other
      },
    }
  }
  pub fn unwrap(self) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::Join(_) | InternalSendAlloc::Spawning => panic!("Item permanently borrowed/leaked"),
    }
  }
}

enum InternalOwned<T> {
  Item(T),
  Borrowed,
}

pub struct Owned<T>(InternalOwned<T>);
impl<T> Owned<T> {
  pub fn new(data:T) -> Self {
    Owned::<T>(InternalOwned::Item(data))
  }
  pub fn unwrap_or(self, other: T) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      other
    }
  }
  pub fn unwrap(self) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      panic!("Item permanently borrowed")
    }
  }
}

pub trait OwnedRetriever<SliceW: SliceWrapper<u8>+Send+'static> {
  fn unwrap(self) -> SliceW;
}

pub trait BatchSpawnable<Alloc:BrotliAlloc+Send+'static, SliceW:SliceWrapper<u8>+Send+'static>
  where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static
{
  type JoinHandle: Joinable<CompressionThreadResult<Alloc>>;
  type FinalJoinHandle: OwnedRetriever<SliceW>;
  // this function takes in a SendAlloc per thread and converts them all into JoinHandle
  // the input is borrowed until the joins complete
  // owned is set to borrowed
  // the final join handle is a r/w lock which will return the SliceW to the owner
  // the FinalJoinHandle is only to be called when each individual JoinHandle has been examined
  fn batch_spawn<F: FnOnce() -> CompressionThreadResult<Alloc> + Send + 'static>(
    input: &mut Owned<SliceW>,
    alloc_per_thread:&mut [SendAlloc<Alloc, Self::JoinHandle>],
    f: F,
  ) -> Self::FinalJoinHandle;
}

pub fn CompressMulti<Alloc:BrotliAlloc+Send+'static, SliceW: SliceWrapper<u8>+Send+'static, Spawner:BatchSpawnable<Alloc, SliceW>> (
  params:&BrotliEncoderParams,
  input: &mut Owned<SliceW>,
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<Alloc, Spawner::JoinHandle>],
  thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {

  Err(())
}

<commit_msg>a bit of trait magic to get CompressMultiSlice to call CompressMulti and allocate a temp buffer before calling it and freeing it after<commit_after>use alloc::{Allocator, SliceWrapper, SliceWrapperMut};
use core::marker::PhantomData;
use super::BrotliAlloc;
use super::backward_references::BrotliEncoderParams;
pub trait Joinable<T:Send+'static>:Sized {
  fn join(self) -> Result<T, ()>;
}

pub struct CompressionThreadResult<Alloc:BrotliAlloc+Send+'static> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  compressed: <Alloc as Allocator<u8>>::AllocatedMemory,
  compressed_size: usize,
  alloc: Alloc,
}
enum InternalSendAlloc<T:Send+'static, Alloc:BrotliAlloc+Send+'static, Join: Joinable<T>>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  A(Alloc),
  Join(Join),
  Spawning(PhantomData<T>),
}
pub struct SendAlloc<T:Send+'static,
                     Alloc:BrotliAlloc +Send+'static,
                     Join:Joinable<T>>(InternalSendAlloc<T, Alloc, Join>)
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send;

impl<T:Send+'static, Alloc:BrotliAlloc+Send+'static,Join:Joinable<T>> SendAlloc<T, Alloc, Join>
  where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  pub fn new(alloc: Alloc) -> Self {
    SendAlloc::<T, Alloc, Join>(InternalSendAlloc::A(alloc))
  }
  pub fn unwrap_or(self, other: Alloc) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::Spawning(_) | InternalSendAlloc::Join(_) => {
        other
      },
    }
  }
  pub fn unwrap(self) -> Alloc {
    match self.0 {
      InternalSendAlloc::A(alloc) => {
        alloc
      },
      InternalSendAlloc::Join(_) | InternalSendAlloc::Spawning(_) => panic!("Item permanently borrowed/leaked"),
    }
  }
}

enum InternalOwned<T> {
  Item(T),
  Borrowed,
}

pub struct Owned<T>(InternalOwned<T>);
impl<T> Owned<T> {
  pub fn new(data:T) -> Self {
    Owned::<T>(InternalOwned::Item(data))
  }
  pub fn unwrap_or(self, other: T) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      other
    }
  }
  pub fn unwrap(self) -> T {
    if let InternalOwned::Item(x) = self.0 {
      x
    } else {
      panic!("Item permanently borrowed")
    }
  }
}

pub trait OwnedRetriever<SliceW: SliceWrapper<u8>+Send+'static> {
  fn view(&self) -> &[u8];
  fn unwrap(self) -> SliceW;
}

pub trait BatchSpawnable<T:Send+'static, Alloc:BrotliAlloc+Send+'static, SliceW:SliceWrapper<u8>+Send+'static>
  where <Alloc as Allocator<u8>>::AllocatedMemory:Send+'static
{
  type JoinHandle: Joinable<T>;
  type FinalJoinHandle: OwnedRetriever<SliceW>;
  // this function takes in a SendAlloc per thread and converts them all into JoinHandle
  // the input is borrowed until the joins complete
  // owned is set to borrowed
  // the final join handle is a r/w lock which will return the SliceW to the owner
  // the FinalJoinHandle is only to be called when each individual JoinHandle has been examined
  fn batch_spawn<F: FnOnce(usize, &SliceW, Alloc) -> T>(
    &mut self,
    input: &mut Owned<SliceW>,
    alloc_per_thread:&mut [SendAlloc<T, Alloc, Self::JoinHandle>],
    f: F,
  ) -> Self::FinalJoinHandle;
}

pub fn CompressMultiSlice<Alloc:BrotliAlloc+Send+'static,
                          Spawner:BatchSpawnable<CompressionThreadResult<Alloc>,
                                                 Alloc,
                                                 <Alloc as Allocator<u8>>::AllocatedMemory>> (
  params:&BrotliEncoderParams,
  input_slice: &[u8],
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>, Alloc, Spawner::JoinHandle>],
  mut thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  let input = if let InternalSendAlloc::A(ref mut alloc) = alloc_per_thread[0].0 {
    let mut input = <Alloc as Allocator<u8>>::alloc_cell(alloc, input_slice.len());
    input.slice_mut().clone_from_slice(input_slice);
    input
  } else {
    <Alloc as Allocator<u8>>::AllocatedMemory::default()
  };
  let mut owned_input = Owned::new(input);
  let ret = CompressMulti(params, &mut owned_input, output, alloc_per_thread,thread_spawner);
  if let InternalSendAlloc::A(ref mut alloc) = alloc_per_thread[0].0 {
    <Alloc as Allocator<u8>>::free_cell(alloc, owned_input.unwrap());
  }
  ret
}

pub fn CompressMulti<Alloc:BrotliAlloc+Send+'static,
                     SliceW: SliceWrapper<u8>+Send+'static,
                     Spawner:BatchSpawnable<CompressionThreadResult<Alloc>,
                                            Alloc,
                                            SliceW>> (
  params:&BrotliEncoderParams,
  owned_input: &mut Owned<SliceW>,
  output: &mut [u8],
  alloc_per_thread:&mut [SendAlloc<CompressionThreadResult<Alloc>, Alloc, Spawner::JoinHandle>],
  mut thread_spawner: Spawner,
) -> Result<usize, ()> where <Alloc as Allocator<u8>>::AllocatedMemory: Send {
  let (mut alloc, alloc_rest) = alloc_per_thread.split_at_mut(1);
  let mut retrieve_owned_input = thread_spawner.batch_spawn(owned_input, alloc_rest, |_index,_input,mut alloc|{
    let mem = <Alloc as Allocator<u8>>::alloc_cell(&mut alloc, 0);
    CompressionThreadResult::<Alloc>{
      compressed:mem,
      compressed_size:0,
      alloc:alloc,
    }
  });
  {
    let input = retrieve_owned_input.view();

  }
  Err(())
}

<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

macro_rules! get_pool {
    ($s:ident; $key:expr) => {
        $s.pools.read($key).await
    };
}

macro_rules! get_mut_pool {
    ($s:ident; $key:expr) => {
        $s.pools.write($key).await
    };
}

macro_rules! rename_pre_sync {
    ($s:expr; $uuid:expr; $new_name:expr; $not_found:expr; $same:expr) => {{
        let old_name = match $s.get_by_uuid($uuid) {
            Some((name, _)) => name,
            None => return $not_found,
        };

        if &*old_name == $new_name {
            return $same;
        }

        if $s.contains_name($new_name) {
            return Err($crate::stratis::StratisError::Msg(format!(
                "Entry with name {} already exists",
                $new_name,
            )));
        }
        old_name
    }};
}

macro_rules! rename_pre_async {
    ($s:expr; $uuid:expr; $new_name:expr; $not_found:expr; $same:expr) => {{
        let old_name = {
            let guard = $s.read($crate::engine::types::LockKey::Uuid($uuid)).await;
            match guard.as_ref().map(|g| g.as_tuple()) {
                Some((name, _, _)) => name,
                None => return $not_found,
            }
        };

        if old_name == $new_name {
            return $same;
        }

        if $s
            .read($crate::engine::types::LockKey::Name($new_name))
            .await
            .is_some()
        {
            return Err($crate::stratis::StratisError::Msg(format!(
                "Entry with name {} already exists",
                $new_name,
            )));
        }
        old_name
    }};
}

macro_rules! rename_filesystem_pre {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_sync!(
            $s.filesystems;
            $uuid;
            $new_name;
            Ok(None);
            Ok(Some(false))
        )
    }}
}

macro_rules! rename_pre_idem_sync {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_sync!(
            $s;
            $uuid;
            $new_name;
            Ok($crate::engine::RenameAction::NoSource);
            Ok($crate::engine::RenameAction::Identity)
        )
    }}
}

macro_rules! rename_pre_idem_async {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_async!(
            $s;
            $uuid;
            $new_name;
            Ok($crate::engine::RenameAction::NoSource);
            Ok($crate::engine::RenameAction::Identity)
        )
    }}
}

macro_rules! rename_filesystem_pre_idem {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_idem_sync!(
            $s.filesystems;
            $uuid;
            $new_name
        )
    }}
}

macro_rules! rename_pool_pre_idem {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_idem_async!(
            $s.pools;
            $uuid;
            $new_name
        )
    }}
}

macro_rules! set_blockdev_user_info {
    ($s:ident; $info:ident) => {
        if $s.user_info.as_ref().map(|x| &**x) != $info {
            $s.user_info = $info.map(|x| x.to_owned());
            true
        } else {
            false
        }
    };
}

macro_rules! device_list_check_num {
    ($vec:ident, ($is_one:tt, $is_many:tt)) => {{
        let joined_string = $vec.join(", ");
        if $vec.len() == 1 {
            format!($is_one, joined_string)
        } else if $vec.len() > 1 {
            format!($is_many, joined_string)
        } else {
            String::new()
        }
    }};
}

macro_rules! create_pool_generate_error_string {
    ($pool_name:ident, $input:ident, $exists:ident) => {
        format!(
            "There was a difference in the blockdevs associated with \
             the existing pool named {} and the input requesting creation \
             of a pool by the same name{}{}",
            $pool_name,
            device_list_check_num!(
                $input,
                (
                    " - the input requests blockdev {} \
                     which does not exist in the current pool",
                    " - the input requests blockdevs {} \
                     which do not exist in the current pool"
                )
            ),
            device_list_check_num!(
                $exists,
                (
                    " - the existing pool contains blockdev {} which was \
                     not requested by the input",
                    " - the existing pool contains blockdevs {} which were \
                     not requested by the input"
                )
            ),
        )
    };
}

#[cfg(test)]
macro_rules! strs_to_paths {
    ($slice:expr) => {
        &$slice.iter().map(std::path::Path::new).collect::<Vec<_>>()
    };
}

macro_rules! init_cache_generate_error_string {
    ($input:ident, $exists:ident) => {
        format!(
            "The input requests initialization of a cache with different block devices \
             from the block devices in the existing cache{}{} ; to \
             resolve this error, the block devices requested in the input should be the \
             same as the block devices in the existing cache.",
            device_list_check_num!(
                $input,
                (
                    "; the existing cache contains \
                     the block device {} which the input did not include",
                    "; the existing cache contains \
                     the block devices {} which the input did not include"
                )
            ),
            device_list_check_num!(
                $exists,
                (
                    "; the input requested block device {} which does not exist in the already \
                     initialized cache",
                    "; the input requested block devices {} which do not exist in the already \
                     initialized cache"
                )
            ),
        )
    };
}

macro_rules! convert_int {
    ($expr:expr, $from_type:ty, $to_type:ty) => {{
        let expr = $expr;
        <$to_type as std::convert::TryFrom<$from_type>>::try_from(expr).map_err(|_| {
            $crate::stratis::StratisError::Msg(format!(
                "Failed to convert integer {} from {} to {}",
                expr,
                stringify!($from_type),
                stringify!($to_type)
            ))
        })
    }};
}

macro_rules! convert_const {
    ($expr:expr, $from_type:ty, $to_type:ty) => {
        <$to_type as std::convert::TryFrom<$from_type>>::try_from($expr)
            .expect(format!("{} is a constant", stringify!($expr)).as_str())
    };
}

#[cfg(test)]
macro_rules! convert_test {
    ($expr:expr, $from_type:ty, $to_type:ty) => {
        <$to_type as std::convert::TryFrom<$from_type>>::try_from($expr).unwrap()
    };
}

// Macro for formatting a Uuid object for use in a device name or in
// a signature buffer.
macro_rules! uuid_to_string {
    ($uuid:expr) => {
        $uuid.as_simple().to_string()
    };
}

#[cfg(test)]
// Macro for allowing a delay for certain operations in tests
macro_rules! retry_operation {
    ($expr:expr) => {
        retry::retry_with_index(retry::delay::Fixed::from_millis(1000).take(2), |i| {
            debug!("Attempt number {} of expression {}", i, stringify!($expr));
            $expr
        })
        .unwrap()
    };
}

macro_rules! pool_enc_to_enc {
    ($ei_option:expr) => {
        match $ei_option {
            Some(pei) => Some($crate::engine::types::EncryptionInfo::try_from(
                pei.clone(),
            )?),
            None => None,
        }
    };
}

#[cfg(test)]
macro_rules! generate_events {
    () => {{
        let cxt = libudev::Context::new().expect("Creating udev context should succeed");
        let mut enumerator =
            libudev::Enumerator::new(&cxt).expect("Creating enumerator should succeed");
        enumerator.match_is_initialized().unwrap();
        let devices = enumerator
            .scan_devices()
            .expect("Scanning udev devices should succeed");

        devices
            .into_iter()
            .filter_map(|dev| {
                let val = dev.property_value($crate::engine::strat_engine::udev::FS_TYPE_KEY);
                if val
                    == Some(std::ffi::OsStr::new(
                        $crate::engine::strat_engine::udev::STRATIS_FS_TYPE,
                    ))
                    || val
                        == Some(std::ffi::OsStr::new(
                            $crate::engine::strat_engine::udev::CRYPTO_FS_TYPE,
                        ))
                {
                    Some($crate::engine::types::UdevEngineEvent::new(
                        libudev::EventType::Add,
                        $crate::engine::types::UdevEngineDevice::from(&dev),
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
    }};
}
<commit_msg>Swap $input and $exists in init_cache_generate_error_string<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

macro_rules! get_pool {
    ($s:ident; $key:expr) => {
        $s.pools.read($key).await
    };
}

macro_rules! get_mut_pool {
    ($s:ident; $key:expr) => {
        $s.pools.write($key).await
    };
}

macro_rules! rename_pre_sync {
    ($s:expr; $uuid:expr; $new_name:expr; $not_found:expr; $same:expr) => {{
        let old_name = match $s.get_by_uuid($uuid) {
            Some((name, _)) => name,
            None => return $not_found,
        };

        if &*old_name == $new_name {
            return $same;
        }

        if $s.contains_name($new_name) {
            return Err($crate::stratis::StratisError::Msg(format!(
                "Entry with name {} already exists",
                $new_name,
            )));
        }
        old_name
    }};
}

macro_rules! rename_pre_async {
    ($s:expr; $uuid:expr; $new_name:expr; $not_found:expr; $same:expr) => {{
        let old_name = {
            let guard = $s.read($crate::engine::types::LockKey::Uuid($uuid)).await;
            match guard.as_ref().map(|g| g.as_tuple()) {
                Some((name, _, _)) => name,
                None => return $not_found,
            }
        };

        if old_name == $new_name {
            return $same;
        }

        if $s
            .read($crate::engine::types::LockKey::Name($new_name))
            .await
            .is_some()
        {
            return Err($crate::stratis::StratisError::Msg(format!(
                "Entry with name {} already exists",
                $new_name,
            )));
        }
        old_name
    }};
}

macro_rules! rename_filesystem_pre {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_sync!(
            $s.filesystems;
            $uuid;
            $new_name;
            Ok(None);
            Ok(Some(false))
        )
    }}
}

macro_rules! rename_pre_idem_sync {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_sync!(
            $s;
            $uuid;
            $new_name;
            Ok($crate::engine::RenameAction::NoSource);
            Ok($crate::engine::RenameAction::Identity)
        )
    }}
}

macro_rules! rename_pre_idem_async {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_async!(
            $s;
            $uuid;
            $new_name;
            Ok($crate::engine::RenameAction::NoSource);
            Ok($crate::engine::RenameAction::Identity)
        )
    }}
}

macro_rules! rename_filesystem_pre_idem {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_idem_sync!(
            $s.filesystems;
            $uuid;
            $new_name
        )
    }}
}

macro_rules! rename_pool_pre_idem {
    ($s:expr; $uuid:expr; $new_name:expr) => {{
        rename_pre_idem_async!(
            $s.pools;
            $uuid;
            $new_name
        )
    }}
}

macro_rules! set_blockdev_user_info {
    ($s:ident; $info:ident) => {
        if $s.user_info.as_ref().map(|x| &**x) != $info {
            $s.user_info = $info.map(|x| x.to_owned());
            true
        } else {
            false
        }
    };
}

macro_rules! device_list_check_num {
    ($vec:ident, ($is_one:tt, $is_many:tt)) => {{
        let joined_string = $vec.join(", ");
        if $vec.len() == 1 {
            format!($is_one, joined_string)
        } else if $vec.len() > 1 {
            format!($is_many, joined_string)
        } else {
            String::new()
        }
    }};
}

macro_rules! create_pool_generate_error_string {
    ($pool_name:ident, $input:ident, $exists:ident) => {
        format!(
            "There was a difference in the blockdevs associated with \
             the existing pool named {} and the input requesting creation \
             of a pool by the same name{}{}",
            $pool_name,
            device_list_check_num!(
                $input,
                (
                    " - the input requests blockdev {} \
                     which does not exist in the current pool",
                    " - the input requests blockdevs {} \
                     which do not exist in the current pool"
                )
            ),
            device_list_check_num!(
                $exists,
                (
                    " - the existing pool contains blockdev {} which was \
                     not requested by the input",
                    " - the existing pool contains blockdevs {} which were \
                     not requested by the input"
                )
            ),
        )
    };
}

#[cfg(test)]
macro_rules! strs_to_paths {
    ($slice:expr) => {
        &$slice.iter().map(std::path::Path::new).collect::<Vec<_>>()
    };
}

macro_rules! init_cache_generate_error_string {
    ($input:ident, $exists:ident) => {
        format!(
            "The input requests initialization of a cache with different block devices \
             from the block devices in the existing cache{}{} ; to \
             resolve this error, the block devices requested in the input should be the \
             same as the block devices in the existing cache.",
            device_list_check_num!(
                $exists,
                (
                    "; the existing cache contains \
                     the block device {} which the input did not include",
                    "; the existing cache contains \
                     the block devices {} which the input did not include"
                )
            ),
            device_list_check_num!(
                $input,
                (
                    "; the input requested block device {} which does not exist in the already \
                     initialized cache",
                    "; the input requested block devices {} which do not exist in the already \
                     initialized cache"
                )
            ),
        )
    };
}

macro_rules! convert_int {
    ($expr:expr, $from_type:ty, $to_type:ty) => {{
        let expr = $expr;
        <$to_type as std::convert::TryFrom<$from_type>>::try_from(expr).map_err(|_| {
            $crate::stratis::StratisError::Msg(format!(
                "Failed to convert integer {} from {} to {}",
                expr,
                stringify!($from_type),
                stringify!($to_type)
            ))
        })
    }};
}

macro_rules! convert_const {
    ($expr:expr, $from_type:ty, $to_type:ty) => {
        <$to_type as std::convert::TryFrom<$from_type>>::try_from($expr)
            .expect(format!("{} is a constant", stringify!($expr)).as_str())
    };
}

#[cfg(test)]
macro_rules! convert_test {
    ($expr:expr, $from_type:ty, $to_type:ty) => {
        <$to_type as std::convert::TryFrom<$from_type>>::try_from($expr).unwrap()
    };
}

// Macro for formatting a Uuid object for use in a device name or in
// a signature buffer.
macro_rules! uuid_to_string {
    ($uuid:expr) => {
        $uuid.as_simple().to_string()
    };
}

#[cfg(test)]
// Macro for allowing a delay for certain operations in tests
macro_rules! retry_operation {
    ($expr:expr) => {
        retry::retry_with_index(retry::delay::Fixed::from_millis(1000).take(2), |i| {
            debug!("Attempt number {} of expression {}", i, stringify!($expr));
            $expr
        })
        .unwrap()
    };
}

macro_rules! pool_enc_to_enc {
    ($ei_option:expr) => {
        match $ei_option {
            Some(pei) => Some($crate::engine::types::EncryptionInfo::try_from(
                pei.clone(),
            )?),
            None => None,
        }
    };
}

#[cfg(test)]
macro_rules! generate_events {
    () => {{
        let cxt = libudev::Context::new().expect("Creating udev context should succeed");
        let mut enumerator =
            libudev::Enumerator::new(&cxt).expect("Creating enumerator should succeed");
        enumerator.match_is_initialized().unwrap();
        let devices = enumerator
            .scan_devices()
            .expect("Scanning udev devices should succeed");

        devices
            .into_iter()
            .filter_map(|dev| {
                let val = dev.property_value($crate::engine::strat_engine::udev::FS_TYPE_KEY);
                if val
                    == Some(std::ffi::OsStr::new(
                        $crate::engine::strat_engine::udev::STRATIS_FS_TYPE,
                    ))
                    || val
                        == Some(std::ffi::OsStr::new(
                            $crate::engine::strat_engine::udev::CRYPTO_FS_TYPE,
                        ))
                {
                    Some($crate::engine::types::UdevEngineEvent::new(
                        libudev::EventType::Add,
                        $crate::engine::types::UdevEngineDevice::from(&dev),
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<_>>()
    }};
}
<|endoftext|>