<commit_before>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: src/obj/voxel/map.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      A voxelization of arbitrary triangles
      into OpenGL-ready cubes.
*/

use math::{ Vec3f };
use primitive::Vertex_PC;
use primitive::Triangle;
use primitive::{ Cube, Cube_Index };

#[path = "../../gl/mod.rs"]
mod gl;
#[path = "../../gl/util.rs"]
mod util;
#[macro_escape]
#[path = "../../gl/check.rs"]
mod check;

macro_rules! index
(
  ($arr:expr[$x:expr][$y:expr][$z:expr]) =>
  (
    $arr[($z * self.resolution * self.resolution) + (y * self.resolution) + x]
  )
)

struct Map
{
  resolution: u32,

  vao: gl::GLuint,
  vbo: gl::GLuint,
  ibo: gl::GLuint,

  voxels: ~[Cube],
  indices: ~[Cube_Index],
  //types: ~[Voxel_Type], /* TODO: Different types of voxels. */
}

impl Map
{
  pub fn new(tris: &[Triangle], res: u32) -> Map
  {
    let mut map = Map
    {
      resolution: res,
      vao: 0,
      vbo: 0,
      ibo: 0,
      voxels: ~[],
      indices: ~[],
      //types: ~[],
    };

    map.voxelize(tris);

    map.vao = check!(gl::gen_vertex_arrays(1))[0]; /* TODO: Check these. */
    map.vbo = check!(gl::gen_buffers(1))[0];
    map.ibo = check!(gl::gen_buffers(1))[0];
    check!(gl::bind_vertex_array(map.vao));
    check!(gl::bind_buffer(gl::ARRAY_BUFFER, map.vbo));
    check!(gl::buffer_data(gl::ARRAY_BUFFER, map.voxels, gl::STATIC_DRAW));

    check!(gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, map.ibo));
    check!(gl::buffer_data(gl::ELEMENT_ARRAY_BUFFER, map.indices, gl::STATIC_DRAW));

    map
  }

  pub fn draw(&self)
  {
    check!(gl::bind_vertex_array(self.vao));
    check!(gl::bind_buffer(gl::ARRAY_BUFFER, self.vbo));
    check!(gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.ibo));

    check!(gl::vertex_attrib_pointer_f32(0, 3, false, (sys::size_of::<Vertex_PC>()) as i32, 0));
    check!(gl::vertex_attrib_pointer_f32(1, 3, false, (sys::size_of::<Vertex_PC>()) as i32, sys::size_of::<Vec3f>() as u32));
    check!(gl::enable_vertex_attrib_array(0));
    check!(gl::enable_vertex_attrib_array(1));

    //check!(gl::polygon_mode(gl::FRONT_AND_BACK, gl::LINE));
    check!(gl::draw_elements(gl::TRIANGLES, self.indices.len() as i32 * 36, gl::UNSIGNED_INT, None));
    check!(gl::polygon_mode(gl::FRONT_AND_BACK, gl::FILL));

    check!(gl::disable_vertex_attrib_array(0));
    check!(gl::disable_vertex_attrib_array(1));
    check!(gl::bind_vertex_array(0));
    check!(gl::bind_buffer(gl::ARRAY_BUFFER, 0));
    check!(gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, 0));
  }

  priv fn voxelize(&mut self, tris: &[Triangle])
  {
    /* Require at least one triangle. */
    assert!(tris.len() >= 1);

    /* Bounding box of vert dimensions. */
    let mut min = Vec3f::new(tris[0].verts[0].position.x, tris[0].verts[0].position.y, tris[0].verts[0].position.z);
    let mut max = Vec3f::new(tris[0].verts[0].position.x, tris[0].verts[0].position.y, tris[0].verts[0].position.z);
    for tris.each |curr|
    {
      for curr.verts.each |vert|
      {
        min.x = cmp::min(min.x, vert.position.x);
        min.y = cmp::min(min.y, vert.position.y);
        min.z = cmp::min(min.z, vert.position.z);

        max.x = cmp::max(max.x, vert.position.x);
        max.y = cmp::max(max.y, vert.position.y);
        max.z = cmp::max(max.z, vert.position.z);
      }
    }
    let center = Vec3f::new(max.x - ((max.x - min.x) / 2.0), max.y - ((max.y - min.y) / 2.0), max.z - ((max.z - min.z) / 2.0));

    /* Calculate, given resolution (how many voxels across), the dimensions of a voxel. */
    let size = cmp::max(max.x - min.x, cmp::max(max.y - min.y, max.z - min.z)) / (self.resolution as f32);

    /* Create 3D array of voxels. */
    let mid_offset = (((self.resolution  as f32) / 2.0) * size);
    self.voxels = vec::with_capacity((f32::pow((self.resolution + 1) as f32, 3.0)) as uint);
    self.indices = vec::with_capacity((f32::pow((self.resolution + 1) as f32, 3.0)) as uint);
    let adjusted_resolution = self.resolution as uint + 1;
    for uint::range(0, adjusted_resolution) |z|
    { for uint::range(0, adjusted_resolution) |y|
      { for uint::range(0, adjusted_resolution) |x|
        {
          let c = Vec3f::new((x as f32 * size) - mid_offset, (y as f32 * size) - mid_offset, (z as f32 * size) - mid_offset) - center;
          let cube = Cube::new(size, c);
          self.voxels.push(cube);

          /* Check if this cube intersects with any triangles. */
          for tris.each |tri|
          {
            if tri_cube_intersect(c, size, tri, x)
            {
              self.indices.push(Cube_Index::new(((z * adjusted_resolution * adjusted_resolution) + (y * adjusted_resolution) + x) as u32));
              break;
            }
          }
        }
      }
    }
    assert!(self.voxels.len() == (f32::pow((adjusted_resolution) as f32, 3.0)) as uint);
  }
}

macro_rules! find_min_max
(
  ($x0:expr, $x1:expr, $x2:expr, $min:expr, $max:expr) =>
  (
    {
      $min = $x0;
      $max = $x0;

      if($x1 < $min){ $min = $x1; }
      if($x1 > $max){ $max = $x1; }
      if($x2 < $min){ $min = $x2; }
      if($x2 > $max){ $max = $x2; }
    }
  )
)

/*======================== X-tests ========================*/
macro_rules! axis_test_x01
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = $a * v0.y - $b * v0.z;
      p2 = $a * v2.y - $b * v2.z;
      if p0 < p2  { min = p0; max = p2;} else { min = p2; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad  { return false; }
    }
  )
)

macro_rules! axis_test_x2
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = $a * v0.y - $b * v0.z;
      p1 = $a * v1.y - $b * v1.z;
      if p0 < p1 { min = p0; max = p1; } else { min = p1; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

/*======================== Y-tests ========================*/

macro_rules! axis_test_y02
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = -$a * v0.x + $b * v0.z;
      p2 = -$a * v2.x + $b * v2.z;
      if p0 < p2 { min = p0; max = p2; } else { min = p2; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

macro_rules! axis_test_y1
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = -$a * v0.x + $b * v0.z;
      p1 = -$a * v1.x + $b * v1.z;
      if p0 < p1 { min = p0; max = p1; } else { min = p1; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

/*======================== Z-tests ========================*/

macro_rules! axis_test_z12
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p1 = $a * v1.x - $b * v1.y;
      p2 = $a * v2.x - $b * v2.y;
      if p2 < p1 { min = p2; max = p1;} else { min = p1; max = p2; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

macro_rules! axis_test_z0
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = $a * v0.x - $b * v0.y;
      p1 = $a * v1.x - $b * v1.y;
      if p0 < p1 { min = p0; max = p1; } else { min = p1; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

#[inline(always)]
priv fn tri_cube_intersect(box_center: Vec3f, box_size: f32, tri: &Triangle, x: uint) -> bool
{
  let mut v0 = Vec3f::zero(), v1 = Vec3f::zero(), v2 = Vec3f::zero();
  let mut min = 0.0, max = 0.0, p0 = 0.0, p1 = 0.0, p2 = 0.0, rad = 0.0, fex = 0.0, fey = 0.0, fez = 0.0;
  let mut normal = Vec3f::zero(), e0 = Vec3f::zero(), e1 = Vec3f::zero(), e2 = Vec3f::zero();

  /* Move everything so that the box's center is in (0, 0, 0). */
  v0 = tri.verts[0].position - box_center;
  v1 = tri.verts[1].position - box_center;
  v2 = tri.verts[2].position - box_center;

  /* Computer triangle edges. */
  e0 = v1 - v0; /* Edge 0. */
  e1 = v2 - v1; /* Edge 1. */
  e2 = v0 - v2; /* Edge 2. */

  /* Bullet 3. */
  fex = f32::abs(e0.x);
  fey = f32::abs(e0.y);
  fez = f32::abs(e0.z);
  axis_test_x01!(e0.z, e0.y, fez, fey);
  axis_test_y02!(e0.z, e0.x, fez, fex);
  axis_test_z12!(e0.y, e0.x, fey, fex);

  fex = f32::abs(e1.x);
  fey = f32::abs(e1.y);
  fez = f32::abs(e1.z);
  axis_test_x01!(e1.z, e1.y, fez, fey);
  axis_test_y02!(e1.z, e1.x, fez, fex);
  axis_test_z0!(e1.y, e1.x, fey, fex);

  fex = f32::abs(e2.x);
  fey = f32::abs(e2.y);
  fez = f32::abs(e2.z);
  axis_test_x2!(e2.z, e2.y, fez, fey);
  axis_test_y1!(e2.z, e2.x, fez, fex);
  axis_test_z12!(e2.y, e2.x, fey, fex);

  /* Bullet 1. */
  /* Test in X-direction */
  find_min_max!(v0.x, v1.x, v2.x, min, max);
  if min > box_size || max < -box_size { return false; }

  /* Test in Y-direction */
  find_min_max!(v0.y, v1.y, v2.y, min, max);
  if min > box_size || max < -box_size { return false; }

  /* Test in Z-direction */
  find_min_max!(v0.z, v1.z, v2.z, min, max);
  if min > box_size || max < -box_size { return false; }

  /* Bullet 2. */
  normal = e0.cross(&e1);
  plane_cube_intersect(&normal, &v0, box_size)
}

#[inline(always)]
priv fn plane_cube_intersect(normal: &Vec3f, vert: &Vec3f, box_size: f32) -> bool
{
  let mut vmin: [f32, ..3] = [0.0, 0.0, 0.0];
  let mut vmax: [f32, ..3] = [0.0, 0.0, 0.0];
  let mut v = 0.0;

  for uint::range(0, 3) |q|
  {
    v = vert[q];
    if normal[q] > 0.0
    {
      vmin[q] = -box_size - v;
      vmax[q] = box_size - v;
    }
    else
    {
      vmin[q] = box_size - v;
      vmax[q] = -box_size - v;
    }
  }
  if (normal[0]*vmin[0]+normal[1]*vmin[1]+normal[2]*vmin[2]) > 0.0 { return false; }
  if (normal[0]*vmax[0]+normal[1]*vmax[1]+normal[2]*vmax[2]) >= 0.0 { return true; }

  false
}

<commit_msg> #12 Voxel map cleanup<commit_after>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: obj/voxel/map.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      A voxelization of arbitrary triangles
      into OpenGL-ready cubes.
*/

use math::{ Vec3f };
use primitive::Vertex_PC;
use primitive::Triangle;
use primitive::{ Cube, Cube_Index };

#[path = "../../gl/mod.rs"]
mod gl;
#[path = "../../gl/util.rs"]
mod util;
#[macro_escape]
#[path = "../../gl/check.rs"]
mod check;

macro_rules! index
(
  ($arr:expr[$x:expr][$y:expr][$z:expr]) =>
  (
    $arr[($z * self.resolution * self.resolution) + (y * self.resolution) + x]
  )
)

struct Map
{
  resolution: u32,

  vao: gl::GLuint,
  vbo: gl::GLuint,
  ibo: gl::GLuint,

  voxels: ~[Cube],
  indices: ~[Cube_Index],
  //types: ~[Voxel_Type], /* TODO: Different types of voxels. */
}

impl Map
{
  pub fn new(tris: &[Triangle], res: u32) -> Map
  {
    let mut map = Map
    {
      resolution: res,
      vao: 0,
      vbo: 0,
      ibo: 0,
      voxels: ~[],
      indices: ~[],
      //types: ~[],
    };

    map.voxelize(tris);

    map.vao = check!(gl::gen_vertex_arrays(1))[0]; /* TODO: Check these. */
    map.vbo = check!(gl::gen_buffers(1))[0];
    map.ibo = check!(gl::gen_buffers(1))[0];
    check!(gl::bind_vertex_array(map.vao));
    check!(gl::bind_buffer(gl::ARRAY_BUFFER, map.vbo));
    check!(gl::buffer_data(gl::ARRAY_BUFFER, map.voxels, gl::STATIC_DRAW));

    check!(gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, map.ibo));
    check!(gl::buffer_data(gl::ELEMENT_ARRAY_BUFFER, map.indices, gl::STATIC_DRAW));

    map
  }

  pub fn draw(&self)
  {
    check!(gl::bind_vertex_array(self.vao));
    check!(gl::bind_buffer(gl::ARRAY_BUFFER, self.vbo));
    check!(gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.ibo));

    check!(gl::vertex_attrib_pointer_f32(0, 3, false, (sys::size_of::<Vertex_PC>()) as i32, 0));
    check!(gl::vertex_attrib_pointer_f32(1, 3, false, (sys::size_of::<Vertex_PC>()) as i32, sys::size_of::<Vec3f>() as u32));
    check!(gl::enable_vertex_attrib_array(0));
    check!(gl::enable_vertex_attrib_array(1));

    //check!(gl::polygon_mode(gl::FRONT_AND_BACK, gl::LINE));
    check!(gl::draw_elements(gl::TRIANGLES, self.indices.len() as i32 * 36, gl::UNSIGNED_INT, None));
    check!(gl::polygon_mode(gl::FRONT_AND_BACK, gl::FILL));

    check!(gl::disable_vertex_attrib_array(0));
    check!(gl::disable_vertex_attrib_array(1));
    check!(gl::bind_vertex_array(0));
    check!(gl::bind_buffer(gl::ARRAY_BUFFER, 0));
    check!(gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, 0));
  }

  priv fn voxelize(&mut self, tris: &[Triangle])
  {
    /* Require at least one triangle. */
    assert!(tris.len() >= 1);

    /* Bounding box of vert dimensions. */
    let mut min = Vec3f::new(tris[0].verts[0].position.x, tris[0].verts[0].position.y, tris[0].verts[0].position.z);
    let mut max = Vec3f::new(tris[0].verts[0].position.x, tris[0].verts[0].position.y, tris[0].verts[0].position.z);
    for tris.each |curr|
    {
      for curr.verts.each |vert|
      {
        min.x = cmp::min(min.x, vert.position.x);
        min.y = cmp::min(min.y, vert.position.y);
        min.z = cmp::min(min.z, vert.position.z);

        max.x = cmp::max(max.x, vert.position.x);
        max.y = cmp::max(max.y, vert.position.y);
        max.z = cmp::max(max.z, vert.position.z);
      }
    }
    let center = Vec3f::new(max.x - ((max.x - min.x) / 2.0), max.y - ((max.y - min.y) / 2.0), max.z - ((max.z - min.z) / 2.0));

    /* Calculate, given resolution (how many voxels across), the dimensions of a voxel. */
    let size = cmp::max(max.x - min.x, cmp::max(max.y - min.y, max.z - min.z)) / (self.resolution as f32);

    /* Create 3D array of voxels. */
    let mid_offset = (((self.resolution  as f32) / 2.0) * size);
    self.voxels = vec::with_capacity((f32::pow((self.resolution + 1) as f32, 3.0)) as uint);
    self.indices = vec::with_capacity((f32::pow((self.resolution + 1) as f32, 3.0)) as uint);
    let adjusted_resolution = self.resolution as uint + 1;
    for uint::range(0, adjusted_resolution) |z|
    { for uint::range(0, adjusted_resolution) |y|
      { for uint::range(0, adjusted_resolution) |x|
        {
          let c = Vec3f::new((x as f32 * size) - mid_offset, (y as f32 * size) - mid_offset, (z as f32 * size) - mid_offset) - center;
          let cube = Cube::new(size, c);
          self.voxels.push(cube);

          /* Check if this cube intersects with any triangles. */
          for tris.each |tri|
          {
            if tri_cube_intersect(c, size, tri, x)
            {
              self.indices.push(Cube_Index::new(((z * adjusted_resolution * adjusted_resolution) + (y * adjusted_resolution) + x) as u32));
              break;
            }
          }
        }
      }
    }
    assert!(self.voxels.len() == (f32::pow((adjusted_resolution) as f32, 3.0)) as uint);
  }
}

macro_rules! find_min_max
(
  ($x0:expr, $x1:expr, $x2:expr) =>
  (
    {
      min = $x0;
      max = $x0;

      if($x1 < min){ min = $x1; }
      if($x1 > max){ max = $x1; }
      if($x2 < min){ min = $x2; }
      if($x2 > max){ max = $x2; }
    }
  )
)

/*======================== X-tests ========================*/
macro_rules! axis_test_x01
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = $a * v0.y - $b * v0.z;
      p2 = $a * v2.y - $b * v2.z;
      if p0 < p2  { min = p0; max = p2;} else { min = p2; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad  { return false; }
    }
  )
)

macro_rules! axis_test_x2
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = $a * v0.y - $b * v0.z;
      p1 = $a * v1.y - $b * v1.z;
      if p0 < p1 { min = p0; max = p1; } else { min = p1; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

/*======================== Y-tests ========================*/

macro_rules! axis_test_y02
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = -$a * v0.x + $b * v0.z;
      p2 = -$a * v2.x + $b * v2.z;
      if p0 < p2 { min = p0; max = p2; } else { min = p2; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

macro_rules! axis_test_y1
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = -$a * v0.x + $b * v0.z;
      p1 = -$a * v1.x + $b * v1.z;
      if p0 < p1 { min = p0; max = p1; } else { min = p1; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

/*======================== Z-tests ========================*/

macro_rules! axis_test_z12
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p1 = $a * v1.x - $b * v1.y;
      p2 = $a * v2.x - $b * v2.y;
      if p2 < p1 { min = p2; max = p1;} else { min = p1; max = p2; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

macro_rules! axis_test_z0
(
  ($a:expr, $b:expr, $fa:expr, $fb:expr) =>
  (
    {
      p0 = $a * v0.x - $b * v0.y;
      p1 = $a * v1.x - $b * v1.y;
      if p0 < p1 { min = p0; max = p1; } else { min = p1; max = p0; }
      rad = $fa * box_size + $fb * box_size;
      if min > rad || max < -rad { return false; }
    }
  )
)

#[inline(always)]
priv fn tri_cube_intersect(box_center: Vec3f, box_size: f32, tri: &Triangle, x: uint) -> bool
{
  let mut v0, v1, v2;
  let mut min, max, p0, p1, p2, rad, fex, fey, fez;
  let mut normal, e0, e1, e2;

  /* Move everything so that the box's center is in (0, 0, 0). */
  v0 = tri.verts[0].position - box_center;
  v1 = tri.verts[1].position - box_center;
  v2 = tri.verts[2].position - box_center;

  /* Computer triangle edges. */
  e0 = v1 - v0; /* Edge 0. */
  e1 = v2 - v1; /* Edge 1. */
  e2 = v0 - v2; /* Edge 2. */

  /* Bullet 3. */
  fex = f32::abs(e0.x);
  fey = f32::abs(e0.y);
  fez = f32::abs(e0.z);
  axis_test_x01!(e0.z, e0.y, fez, fey);
  axis_test_y02!(e0.z, e0.x, fez, fex);
  axis_test_z12!(e0.y, e0.x, fey, fex);

  fex = f32::abs(e1.x);
  fey = f32::abs(e1.y);
  fez = f32::abs(e1.z);
  axis_test_x01!(e1.z, e1.y, fez, fey);
  axis_test_y02!(e1.z, e1.x, fez, fex);
  axis_test_z0!(e1.y, e1.x, fey, fex);

  fex = f32::abs(e2.x);
  fey = f32::abs(e2.y);
  fez = f32::abs(e2.z);
  axis_test_x2!(e2.z, e2.y, fez, fey);
  axis_test_y1!(e2.z, e2.x, fez, fex);
  axis_test_z12!(e2.y, e2.x, fey, fex);

  /* Bullet 1. */
  /* Test in X-direction */
  find_min_max!(v0.x, v1.x, v2.x);
  if min > box_size || max < -box_size { return false; }

  /* Test in Y-direction */
  find_min_max!(v0.y, v1.y, v2.y);
  if min > box_size || max < -box_size { return false; }

  /* Test in Z-direction */
  find_min_max!(v0.z, v1.z, v2.z);
  if min > box_size || max < -box_size { return false; }

  /* Bullet 2. */
  normal = e0.cross(&e1);
  plane_cube_intersect(&normal, &v0, box_size)
}

#[inline(always)]
priv fn plane_cube_intersect(normal: &Vec3f, vert: &Vec3f, box_size: f32) -> bool
{
  let mut vmin: [f32, ..3] = [0.0, 0.0, 0.0];
  let mut vmax: [f32, ..3] = [0.0, 0.0, 0.0];
  let mut v = 0.0;

  for uint::range(0, 3) |q|
  {
    v = vert[q];
    if normal[q] > 0.0
    {
      vmin[q] = -box_size - v;
      vmax[q] = box_size - v;
    }
    else
    {
      vmin[q] = box_size - v;
      vmax[q] = -box_size - v;
    }
  }
  if (normal[0]*vmin[0]+normal[1]*vmin[1]+normal[2]*vmin[2]) > 0.0 { return false; }
  if (normal[0]*vmax[0]+normal[1]*vmax[1]+normal[2]*vmax[2]) >= 0.0 { return true; }

  false
}

<|endoftext|>


<commit_before>use super::parser;
use super::{Object, ObjectId, Stream};
use std::collections::BTreeMap;
use std::str::FromStr;

use rayon::prelude::*;

#[derive(Debug)]
pub struct ObjectStream {
	pub objects: BTreeMap<ObjectId, Object>,
}

impl ObjectStream {
	pub fn new(stream: &mut Stream) -> Option<ObjectStream> {
		stream.decompress();

		if stream.content.is_empty() {
			return Some(ObjectStream { objects: BTreeMap::new() });
		}

		let first_offset = stream.dict.get(b"First").and_then(Object::as_i64)? as usize;
		let _count = stream.dict.get(b"N").and_then(Object::as_i64)? as usize;

		let index_block = stream.content.get(..first_offset)?;

		let numbers_str = std::str::from_utf8(index_block).ok()?;
		let numbers: Vec<_> = numbers_str.par_split_whitespace().map(|number| u32::from_str(number).ok()).collect();
		let len = numbers.len() / 2 * 2; // Ensure only pairs.

		let objects = numbers[..len].par_chunks(2).filter_map(|chunk| {
			let id = chunk[0]?;
			let offset = first_offset + chunk[1]? as usize;

			let object = parser::direct_object().parse(&stream.content[offset..]).ok()?;

			Some(((id, 0), object))
		}).collect();

		Some(ObjectStream{ objects })
	}
}
<commit_msg>Ease off on rayon a bit.<commit_after>use super::parser;
use super::{Object, ObjectId, Stream};
use std::collections::BTreeMap;
use std::str::FromStr;

use rayon::prelude::*;

#[derive(Debug)]
pub struct ObjectStream {
	pub objects: BTreeMap<ObjectId, Object>,
}

impl ObjectStream {
	pub fn new(stream: &mut Stream) -> Option<ObjectStream> {
		stream.decompress();

		if stream.content.is_empty() {
			return Some(ObjectStream { objects: BTreeMap::new() });
		}

		let first_offset = stream.dict.get(b"First").and_then(Object::as_i64)? as usize;
		let _count = stream.dict.get(b"N").and_then(Object::as_i64)? as usize;

		let index_block = stream.content.get(..first_offset)?;

		let numbers_str = std::str::from_utf8(index_block).ok()?;
		let numbers: Vec<_> = numbers_str.split_whitespace().map(|number| u32::from_str(number).ok()).collect();
		let len = numbers.len() / 2 * 2; // Ensure only pairs.

		let objects = numbers[..len].par_chunks(2).filter_map(|chunk| {
			let id = chunk[0]?;
			let offset = first_offset + chunk[1]? as usize;

			let object = parser::direct_object().parse(&stream.content[offset..]).ok()?;

			Some(((id, 0), object))
		}).collect();

		Some(ObjectStream{ objects })
	}
}
<|endoftext|>


<commit_before>use af;
use loss;
use activations;
use layer::{Layer};
use optimizer::Optimizer;
use af::{Array};
use std::collections::HashMap;
use std::default::Default;

pub struct SGD {
  name: &'static str,
  learning_rate: f32,
  momemtum: f32,
  decay: f32,
  nesterov: bool,
  clip_grad: u64,
  iter: u64,
}

impl Default for SGD {
  fn default() -> SGD { //docs say Self
    SGD {
      name: "SGD",
      learning_rate: 0.01,
      momemtum: 0.0,
      decay: 0.0,
      nesterov: false,
      clip_grad: 0,
      iter: 0,
    }
  }
}

impl Optimizer for SGD {
  fn new(params: &HashMap<&str, &str>) -> SGD {
    SGD{
      name: "SGD",
      learning_rate: params.get("learning_rate").unwrap().parse::<f32>().unwrap(),
      momemtum: params.get("momemtum").unwrap().parse::<f32>().unwrap(),
      decay: params.get("decay").unwrap().parse::<f32>().unwrap(),
      nesterov: params.get("nesterov").unwrap().parse::<bool>().unwrap(),
      clip_grad: params.get("clip_grad").unwrap().parse::<u64>().unwrap(),
      iter: 0,
    }
  }

  fn grads(&self, prediction: &Array, target: &Array
           , loss: &'static str, activation_type: &'static str) -> Array
  {
    // d_L = d_loss * d(z) where z = activation w/out non-linearity
    let d_loss = loss::get_loss_derivative(loss, prediction, target).unwrap();
    let d_z = activations::get_activation_derivative(activation_type, prediction).unwrap();
    af::mul(&d_loss, &d_z).unwrap()
  }

  //TODO: Add nesterov & momentum
  fn update_one(&self, layer: &mut Box<Layer>, prev_activation: &Array, diffs: &Array){
    // W = W - lr * a_{l-1} * d_l
    let weights = layer.get_weights();
    for i in (0..weights.len()) { // for all weights in this layer
      let update = af::matmul(diffs, prev_activation, af::MatProp::NONE, af::MatProp::TRANS).unwrap();
      layer.set_weights(&af::sub(&weights[i], &af::mul(&self.learning_rate, &update).unwrap()).unwrap(), i);
    }
    // b = b - lr * d_l
    let mut biases = layer.get_bias();
    for i in (0..biases.len()) {
      layer.set_bias(&af::sub(&biases[i], &af::mul(&self.learning_rate, diffs).unwrap()).unwrap(), i);
    }
  }

  fn update(&mut self, layers: &mut Vec<Box<Layer>>
            , prediction: &Array
            , target: &Array
            , loss: &'static str) -> (f32, Array)
  {
    self.iter += 1;
    self.learning_rate *= (1.0 / (1.0 + self.decay * (self.iter as f32)));
    let last_index = layers.len() - 1;
    let prev_activation = layers[last_index].get_input();
    let diffs = self.grads(prediction
                           , target
                           , loss
                           , layers[last_index].get_activation_type());
    self.update_one(&mut layers[last_index], &prev_activation, &diffs);

    // Verify:: Don't backprop to 1st layer
    for i in (1..last_index).rev() {
      // d_l = (W_{l+1}^T * d_{l+1}) .* derivative(z) where z = activation w/out non-linearity
      let prev_activation = layers[i].get_input();
      let grad = activations::get_activation_derivative(layers[i].get_activation_type(), &prev_activation).unwrap();
      let diffs = layers[i].backward(&diffs, &grad);
      self.update_one(&mut layers[i], &prev_activation, &diffs);
    }

    (loss::get_loss(loss, prediction, target).unwrap(), prediction.clone())
  }

  fn info(&self){
    println!("name:          {}", self.name);
    println!("learning_rate: {}", self.name);
    println!("momemtum:      {}", self.name);
    println!("decay:         {}", self.name);
    println!("nesterov:      {}", self.name);
    println!("clip_grad:     {}", self.name);
  }
}
<commit_msg>ensure that the default learning rate is 1e-3<commit_after>use af;
use loss;
use activations;
use layer::{Layer};
use optimizer::Optimizer;
use af::{Array};
use std::collections::HashMap;
use std::default::Default;

pub struct SGD {
  name: &'static str,
  learning_rate: f32,
  momemtum: f32,
  decay: f32,
  nesterov: bool,
  clip_grad: u64,
  iter: u64,
}

impl Default for SGD {
  fn default() -> SGD { //docs say Self
    SGD {
      name: "SGD",
      learning_rate: 0.001,
      momemtum: 0.0,
      decay: 0.0,
      nesterov: false,
      clip_grad: 0,
      iter: 0,
    }
  }
}

impl Optimizer for SGD {
  fn new(params: &HashMap<&str, &str>) -> SGD {
    SGD{
      name: "SGD",
      learning_rate: params.get("learning_rate").unwrap().parse::<f32>().unwrap(),
      momemtum: params.get("momemtum").unwrap().parse::<f32>().unwrap(),
      decay: params.get("decay").unwrap().parse::<f32>().unwrap(),
      nesterov: params.get("nesterov").unwrap().parse::<bool>().unwrap(),
      clip_grad: params.get("clip_grad").unwrap().parse::<u64>().unwrap(),
      iter: 0,
    }
  }

  fn grads(&self, prediction: &Array, target: &Array
           , loss: &'static str, activation_type: &'static str) -> Array
  {
    // d_L = d_loss * d(z) where z = activation w/out non-linearity
    let d_loss = loss::get_loss_derivative(loss, prediction, target).unwrap();
    let d_z = activations::get_activation_derivative(activation_type, prediction).unwrap();
    af::mul(&d_loss, &d_z).unwrap()
  }

  //TODO: Add nesterov & momentum
  fn update_one(&self, layer: &mut Box<Layer>, prev_activation: &Array, diffs: &Array){
    // W = W - lr * a_{l-1} * d_l
    let weights = layer.get_weights();
    for i in (0..weights.len()) { // for all weights in this layer
      let update = af::matmul(diffs, prev_activation, af::MatProp::NONE, af::MatProp::TRANS).unwrap();
      layer.set_weights(&af::sub(&weights[i], &af::mul(&self.learning_rate, &update).unwrap()).unwrap(), i);
    }
    // b = b - lr * d_l
    let mut biases = layer.get_bias();
    for i in (0..biases.len()) {
      layer.set_bias(&af::sub(&biases[i], &af::mul(&self.learning_rate, diffs).unwrap()).unwrap(), i);
    }
  }

  fn update(&mut self, layers: &mut Vec<Box<Layer>>
            , prediction: &Array
            , target: &Array
            , loss: &'static str) -> (f32, Array)
  {
    self.iter += 1;
    self.learning_rate *= (1.0 / (1.0 + self.decay * (self.iter as f32)));
    let last_index = layers.len() - 1;
    let prev_activation = layers[last_index].get_input();
    let diffs = self.grads(prediction
                           , target
                           , loss
                           , layers[last_index].get_activation_type());
    self.update_one(&mut layers[last_index], &prev_activation, &diffs);

    // Verify:: Don't backprop to 1st layer
    for i in (1..last_index).rev() {
      // d_l = (W_{l+1}^T * d_{l+1}) .* derivative(z) where z = activation w/out non-linearity
      let prev_activation = layers[i].get_input();
      let grad = activations::get_activation_derivative(layers[i].get_activation_type(), &prev_activation).unwrap();
      let diffs = layers[i].backward(&diffs, &grad);
      self.update_one(&mut layers[i], &prev_activation, &diffs);
    }

    (loss::get_loss(loss, prediction, target).unwrap(), prediction.clone())
  }

  fn info(&self){
    println!("name:          {}", self.name);
    println!("learning_rate: {}", self.name);
    println!("momemtum:      {}", self.name);
    println!("decay:         {}", self.name);
    println!("nesterov:      {}", self.name);
    println!("clip_grad:     {}", self.name);
  }
}
<|endoftext|>


<commit_before>extern crate encoding;

use std::fmt;

use self::encoding::types::EncodingRef;

/// ParseOptions allows setting options for parsing MO catalogs.
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        ParseOptions { force_encoding: None }
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(&mut self, encoding: EncodingRef) -> &mut Self {
        self.force_encoding = Some(encoding);
        self
    }
}

// Cannot derive as Encoding does not implement Debug.
impl fmt::Debug for ParseOptions {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let mut debug_fmt = fmt.debug_struct("ParseOptions");
        match self.force_encoding {
            opt @ Some(_) => {
                debug_fmt.field("force_encoding", &opt.map(|e| e.name()));
            }
            opt @ None => {
                // HACK: convert Option<EncodingRef> to Option<()> with map()
                // to get a Debug impl.
                debug_fmt.field("force_encoding", &opt.map(|_| ()));
            }
        }
        debug_fmt.finish()
    }
}

#[test]
fn test_parse_options() {
    let enc = self::encoding::label::encoding_from_whatwg_label("cp1257").unwrap();
    panic!("{:?}", ParseOptions::new().force_encoding(enc));
}
<commit_msg>Remove debugging fluff<commit_after>extern crate encoding;

use std::fmt;

use self::encoding::types::EncodingRef;

/// ParseOptions allows setting options for parsing MO catalogs.
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        ParseOptions { force_encoding: None }
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(&mut self, encoding: EncodingRef) -> &mut Self {
        self.force_encoding = Some(encoding);
        self
    }
}

// Cannot derive as Encoding does not implement Debug.
impl fmt::Debug for ParseOptions {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let mut debug_fmt = fmt.debug_struct("ParseOptions");
        match self.force_encoding {
            opt @ Some(_) => {
                debug_fmt.field("force_encoding", &opt.map(|e| e.name()));
            }
            opt @ None => {
                // HACK: convert Option<EncodingRef> to Option<()> with map()
                // to get a Debug impl.
                debug_fmt.field("force_encoding", &opt.map(|_| ()));
            }
        }
        debug_fmt.finish()
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use crate::controllers::frontend_prelude::*;

use crate::controllers::helpers::*;

use crate::controllers::helpers::pagination::{Paginated, PaginationOptions};
use crate::models::{
    CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
};
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
use crate::views::{EncodableMe, EncodablePrivateUser, EncodableVersion, OwnedCrate};

/// Handles the `GET /me` route.
pub fn me(req: &mut dyn RequestExt) -> EndpointResult {
    let user_id = req.authenticate()?.forbid_api_token_auth()?.user_id();
    let conn = req.db_conn()?;

    let (user, verified, email, verification_sent): (User, Option<bool>, Option<String>, bool) =
        users::table
            .find(user_id)
            .left_join(emails::table)
            .select((
                users::all_columns,
                emails::verified.nullable(),
                emails::email.nullable(),
                emails::token_generated_at.nullable().is_not_null(),
            ))
            .first(&*conn)?;

    let owned_crates = CrateOwner::by_owner_kind(OwnerKind::User)
        .inner_join(crates::table)
        .filter(crate_owners::owner_id.eq(user_id))
        .select((crates::id, crates::name, crate_owners::email_notifications))
        .order(crates::name.asc())
        .load(&*conn)?
        .into_iter()
        .map(|(id, name, email_notifications)| OwnedCrate {
            id,
            name,
            email_notifications,
        })
        .collect();

    let verified = verified.unwrap_or(false);
    let verification_sent = verified || verification_sent;
    Ok(req.json(&EncodableMe {
        user: EncodablePrivateUser::from(user, email, verified, verification_sent),
        owned_crates,
    }))
}

/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::any;

    let authenticated_user = req.authenticate()?.forbid_api_token_auth()?;
    let user = authenticated_user.user();

    let followed_crates = Follow::belonging_to(&user).select(follows::crate_id);
    let query = versions::table
        .inner_join(crates::table)
        .left_outer_join(users::table)
        .filter(crates::id.eq(any(followed_crates)))
        .order(versions::created_at.desc())
        .select((
            versions::all_columns,
            crates::name,
            users::all_columns.nullable(),
        ))
        .pages_pagination(PaginationOptions::builder().gather(req)?);
    let conn = req.db_conn()?;
    let data: Paginated<(Version, String, Option<User>)> = query.load(&*conn)?;
    let more = data.next_page_params().is_some();
    let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
    let data = data
        .into_iter()
        .zip(VersionOwnerAction::for_versions(&conn, &versions)?.into_iter())
        .map(|((v, cn, pb), voas)| (v, cn, pb, voas));

    let versions = data
        .into_iter()
        .map(|(version, crate_name, published_by, actions)| {
            EncodableVersion::from(version, &crate_name, published_by, actions)
        })
        .collect();

    #[derive(Serialize)]
    struct R {
        versions: Vec<EncodableVersion>,
        meta: Meta,
    }
    #[derive(Serialize)]
    struct Meta {
        more: bool,
    }
    Ok(req.json(&R {
        versions,
        meta: Meta { more },
    }))
}

/// Handles the `PUT /users/:user_id` route.
pub fn update_user(req: &mut dyn RequestExt) -> EndpointResult {
    use self::emails::user_id;
    use diesel::insert_into;

    let authenticated_user = req.authenticate()?;

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let param_user_id = &req.params()["user_id"];
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if &user.id.to_string() != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    #[derive(Deserialize)]
    struct UserUpdate {
        user: User,
    }

    #[derive(Deserialize)]
    struct User {
        email: Option<String>,
    }

    let user_update: UserUpdate =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let user_email = match &user_update.user.email {
        Some(email) => email.trim(),
        None => return Err(bad_request("empty email rejected")),
    };

    if user_email.is_empty() {
        return Err(bad_request("empty email rejected"));
    }

    conn.transaction::<_, Box<dyn AppError>, _>(|| {
        let new_email = NewEmail {
            user_id: user.id,
            email: user_email,
        };

        let token: String = insert_into(emails::table)
            .values(&new_email)
            .on_conflict(user_id)
            .do_update()
            .set(&new_email)
            .returning(emails::token)
            .get_result(&*conn)
            .map_err(|_| server_error("Error in creating token"))?;

        // This swallows any errors that occur while attempting to send the email. Some users have
        // an invalid email set in their GitHub profile, and we should let them sign in even though
        // we're trying to silently use their invalid address during signup and can't send them an
        // email. They'll then have to provide a valid email address.
        let _ = req
            .app()
            .emails
            .send_user_confirm(user_email, &user.gh_login, &token);

        Ok(())
    })?;

    ok_true()
}

/// Handles the `PUT /confirm/:email_token` route
pub fn confirm_user_email(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::update;

    let conn = req.db_conn()?;
    let req_token = &req.params()["email_token"];

    let updated_rows = update(emails::table.filter(emails::token.eq(req_token)))
        .set(emails::verified.eq(true))
        .execute(&*conn)?;

    if updated_rows == 0 {
        return Err(bad_request("Email belonging to token not found."));
    }

    ok_true()
}

/// Handles `PUT /user/:user_id/resend` route
pub fn regenerate_token_and_send(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::sql;
    use diesel::update;

    let param_user_id = req.params()["user_id"]
        .parse::<i32>()
        .chain_error(|| bad_request("invalid user_id"))?;
    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if user.id != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    conn.transaction(|| {
        let email: Email = update(Email::belonging_to(&user))
            .set(emails::token.eq(sql("DEFAULT")))
            .get_result(&*conn)
            .map_err(|_| bad_request("Email could not be found"))?;

        req.app()
            .emails
            .send_user_confirm(&email.email, &user.gh_login, &email.token)
    })?;

    ok_true()
}

/// Handles `PUT /me/email_notifications` route
pub fn update_email_notifications(req: &mut dyn RequestExt) -> EndpointResult {
    use self::crate_owners::dsl::*;
    use diesel::pg::upsert::excluded;

    #[derive(Deserialize)]
    struct CrateEmailNotifications {
        id: i32,
        email_notifications: bool,
    }

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    let updates: HashMap<i32, bool> = serde_json::from_str::<Vec<CrateEmailNotifications>>(&body)
        .map_err(|_| bad_request("invalid json request"))?
        .iter()
        .map(|c| (c.id, c.email_notifications))
        .collect();

    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    // Build inserts from existing crates belonging to the current user
    let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
        .filter(owner_id.eq(user_id))
        .select((crate_id, owner_id, owner_kind, email_notifications))
        .load(&*conn)?
        .into_iter()
        // Remove records whose `email_notifications` will not change from their current value
        .map(
            |(c_id, o_id, o_kind, e_notifications): (i32, i32, i32, bool)| {
                let current_e_notifications = *updates.get(&c_id).unwrap_or(&e_notifications);
                (
                    crate_id.eq(c_id),
                    owner_id.eq(o_id),
                    owner_kind.eq(o_kind),
                    email_notifications.eq(current_e_notifications),
                )
            },
        )
        .collect::<Vec<_>>();

    // Upsert crate owners; this should only actually exectute updates
    diesel::insert_into(crate_owners)
        .values(&to_insert)
        .on_conflict((crate_id, owner_id, owner_kind))
        .do_update()
        .set(email_notifications.eq(excluded(email_notifications)))
        .execute(&*conn)?;

    ok_true()
}
<commit_msg>controllers::user::me: Use `json!` macro to simplify JSON serialization code<commit_after>use std::collections::HashMap;

use crate::controllers::frontend_prelude::*;

use crate::controllers::helpers::*;

use crate::controllers::helpers::pagination::{Paginated, PaginationOptions};
use crate::models::{
    CrateOwner, Email, Follow, NewEmail, OwnerKind, User, Version, VersionOwnerAction,
};
use crate::schema::{crate_owners, crates, emails, follows, users, versions};
use crate::views::{EncodableMe, EncodablePrivateUser, EncodableVersion, OwnedCrate};

/// Handles the `GET /me` route.
pub fn me(req: &mut dyn RequestExt) -> EndpointResult {
    let user_id = req.authenticate()?.forbid_api_token_auth()?.user_id();
    let conn = req.db_conn()?;

    let (user, verified, email, verification_sent): (User, Option<bool>, Option<String>, bool) =
        users::table
            .find(user_id)
            .left_join(emails::table)
            .select((
                users::all_columns,
                emails::verified.nullable(),
                emails::email.nullable(),
                emails::token_generated_at.nullable().is_not_null(),
            ))
            .first(&*conn)?;

    let owned_crates = CrateOwner::by_owner_kind(OwnerKind::User)
        .inner_join(crates::table)
        .filter(crate_owners::owner_id.eq(user_id))
        .select((crates::id, crates::name, crate_owners::email_notifications))
        .order(crates::name.asc())
        .load(&*conn)?
        .into_iter()
        .map(|(id, name, email_notifications)| OwnedCrate {
            id,
            name,
            email_notifications,
        })
        .collect();

    let verified = verified.unwrap_or(false);
    let verification_sent = verified || verification_sent;
    Ok(req.json(&EncodableMe {
        user: EncodablePrivateUser::from(user, email, verified, verification_sent),
        owned_crates,
    }))
}

/// Handles the `GET /me/updates` route.
pub fn updates(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::any;

    let authenticated_user = req.authenticate()?.forbid_api_token_auth()?;
    let user = authenticated_user.user();

    let followed_crates = Follow::belonging_to(&user).select(follows::crate_id);
    let query = versions::table
        .inner_join(crates::table)
        .left_outer_join(users::table)
        .filter(crates::id.eq(any(followed_crates)))
        .order(versions::created_at.desc())
        .select((
            versions::all_columns,
            crates::name,
            users::all_columns.nullable(),
        ))
        .pages_pagination(PaginationOptions::builder().gather(req)?);
    let conn = req.db_conn()?;
    let data: Paginated<(Version, String, Option<User>)> = query.load(&*conn)?;
    let more = data.next_page_params().is_some();
    let versions = data.iter().map(|(v, _, _)| v).cloned().collect::<Vec<_>>();
    let data = data
        .into_iter()
        .zip(VersionOwnerAction::for_versions(&conn, &versions)?.into_iter())
        .map(|((v, cn, pb), voas)| (v, cn, pb, voas));

    let versions = data
        .into_iter()
        .map(|(version, crate_name, published_by, actions)| {
            EncodableVersion::from(version, &crate_name, published_by, actions)
        })
        .collect::<Vec<_>>();

    Ok(req.json(&json!({
        "versions": versions,
        "meta": { "more": more },
    })))
}

/// Handles the `PUT /users/:user_id` route.
pub fn update_user(req: &mut dyn RequestExt) -> EndpointResult {
    use self::emails::user_id;
    use diesel::insert_into;

    let authenticated_user = req.authenticate()?;

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;

    let param_user_id = &req.params()["user_id"];
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if &user.id.to_string() != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    #[derive(Deserialize)]
    struct UserUpdate {
        user: User,
    }

    #[derive(Deserialize)]
    struct User {
        email: Option<String>,
    }

    let user_update: UserUpdate =
        serde_json::from_str(&body).map_err(|_| bad_request("invalid json request"))?;

    let user_email = match &user_update.user.email {
        Some(email) => email.trim(),
        None => return Err(bad_request("empty email rejected")),
    };

    if user_email.is_empty() {
        return Err(bad_request("empty email rejected"));
    }

    conn.transaction::<_, Box<dyn AppError>, _>(|| {
        let new_email = NewEmail {
            user_id: user.id,
            email: user_email,
        };

        let token: String = insert_into(emails::table)
            .values(&new_email)
            .on_conflict(user_id)
            .do_update()
            .set(&new_email)
            .returning(emails::token)
            .get_result(&*conn)
            .map_err(|_| server_error("Error in creating token"))?;

        // This swallows any errors that occur while attempting to send the email. Some users have
        // an invalid email set in their GitHub profile, and we should let them sign in even though
        // we're trying to silently use their invalid address during signup and can't send them an
        // email. They'll then have to provide a valid email address.
        let _ = req
            .app()
            .emails
            .send_user_confirm(user_email, &user.gh_login, &token);

        Ok(())
    })?;

    ok_true()
}

/// Handles the `PUT /confirm/:email_token` route
pub fn confirm_user_email(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::update;

    let conn = req.db_conn()?;
    let req_token = &req.params()["email_token"];

    let updated_rows = update(emails::table.filter(emails::token.eq(req_token)))
        .set(emails::verified.eq(true))
        .execute(&*conn)?;

    if updated_rows == 0 {
        return Err(bad_request("Email belonging to token not found."));
    }

    ok_true()
}

/// Handles `PUT /user/:user_id/resend` route
pub fn regenerate_token_and_send(req: &mut dyn RequestExt) -> EndpointResult {
    use diesel::dsl::sql;
    use diesel::update;

    let param_user_id = req.params()["user_id"]
        .parse::<i32>()
        .chain_error(|| bad_request("invalid user_id"))?;
    let authenticated_user = req.authenticate()?;
    let conn = req.db_conn()?;
    let user = authenticated_user.user();

    // need to check if current user matches user to be updated
    if user.id != param_user_id {
        return Err(bad_request("current user does not match requested user"));
    }

    conn.transaction(|| {
        let email: Email = update(Email::belonging_to(&user))
            .set(emails::token.eq(sql("DEFAULT")))
            .get_result(&*conn)
            .map_err(|_| bad_request("Email could not be found"))?;

        req.app()
            .emails
            .send_user_confirm(&email.email, &user.gh_login, &email.token)
    })?;

    ok_true()
}

/// Handles `PUT /me/email_notifications` route
pub fn update_email_notifications(req: &mut dyn RequestExt) -> EndpointResult {
    use self::crate_owners::dsl::*;
    use diesel::pg::upsert::excluded;

    #[derive(Deserialize)]
    struct CrateEmailNotifications {
        id: i32,
        email_notifications: bool,
    }

    let mut body = String::new();
    req.body().read_to_string(&mut body)?;
    let updates: HashMap<i32, bool> = serde_json::from_str::<Vec<CrateEmailNotifications>>(&body)
        .map_err(|_| bad_request("invalid json request"))?
        .iter()
        .map(|c| (c.id, c.email_notifications))
        .collect();

    let user_id = req.authenticate()?.user_id();
    let conn = req.db_conn()?;

    // Build inserts from existing crates belonging to the current user
    let to_insert = CrateOwner::by_owner_kind(OwnerKind::User)
        .filter(owner_id.eq(user_id))
        .select((crate_id, owner_id, owner_kind, email_notifications))
        .load(&*conn)?
        .into_iter()
        // Remove records whose `email_notifications` will not change from their current value
        .map(
            |(c_id, o_id, o_kind, e_notifications): (i32, i32, i32, bool)| {
                let current_e_notifications = *updates.get(&c_id).unwrap_or(&e_notifications);
                (
                    crate_id.eq(c_id),
                    owner_id.eq(o_id),
                    owner_kind.eq(o_kind),
                    email_notifications.eq(current_e_notifications),
                )
            },
        )
        .collect::<Vec<_>>();

    // Upsert crate owners; this should only actually exectute updates
    diesel::insert_into(crate_owners)
        .values(&to_insert)
        .on_conflict((crate_id, owner_id, owner_kind))
        .do_update()
        .set(email_notifications.eq(excluded(email_notifications)))
        .execute(&*conn)?;

    ok_true()
}
<|endoftext|>


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

// This is a port of the pcre project's `pcredemo` sample using rust-pcre bindings.

extern mod extra;
extern mod pcre;

use extra::enum_set::{EnumSet};
use extra::getopts::{Opt, getopts, optflag};
use extra::treemap::{TreeMap};
use pcre::{CompileOption, Match, Pcre, pcre_version};
use std::os;

fn print_usage(program: &str, opts: &[Opt]) {
    drop(opts);
    println!("Usage: {} [options] pattern subject", program);
    println!("Options:");
    println!("    -g                  Find all matches");
    println!("    -h, --help          Print usage and exit");
    println!("    --version           Print version information and exit");
}

fn print_version_info() {
    println!("rust-pcre 0.1 compiled against libpcre {}", pcre_version());
}

fn print_match(m: &Match, name_table: &TreeMap<~str, ~[uint]>) {
    println!("Match succeeded at offset {:u}", m.group_start(0u));

    // Show captured substrings by number.
    let mut i = 0u;
    while i < m.string_count() {
        println!("{:2u}: {:s}", i, m.group(i));
        i += 1;
    }

    let name_count = name_table.len();
    if name_count <= 0 {
        println!("No named substrings");
    } else {
        println!("Named substrings:");
        for (name, n_vec) in name_table.iter() {
            for n in n_vec.iter() {
                println!("({:u}) {:s}: {:s}", *n, *name, m.group(*n));
            }
        }
    }
}

fn main() {
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        optflag("g"),
        optflag("h"),
        optflag("help"),
        optflag("version")
    ];

    let opt_matches = match getopts(args.tail(), opts) {
        Ok(m)  => m,
        Err(f) => {
            println!("Error: {}", f.to_err_msg());
            os::set_exit_status(1);
            return;
        }
    };

    if opt_matches.opt_present("h") || opt_matches.opt_present("help") {
        print_usage(program, opts);
        return;
    }

    if opt_matches.opt_present("version") {
        print_version_info();
        return;
    }

    let find_all = opt_matches.opt_present("g");
    if opt_matches.free.len() == 0 {
        println!("Error: No pattern");
        os::set_exit_status(1);
        return;
    } else if opt_matches.free.len() == 1 {
        println!("Error: No subject");
        os::set_exit_status(1);
        return;
    } else if opt_matches.free.len() > 2 {
        println!("Error: Too many command line arguments");
        os::set_exit_status(1);
        return;
    }

    let pattern = opt_matches.free[0].clone();
    let subject = opt_matches.free[1].clone();

    let mut compile_options: EnumSet<CompileOption> = EnumSet::empty();
    compile_options.add(pcre::DupNames);
    let re = match Pcre::compile_with_options(pattern, &compile_options) {
        Err(err) => {
            println!("Error: The pattern could not be compiled: {:s}", err.to_str());
            os::set_exit_status(1);
            return;
        },
        Ok(re) => re
    };
    let name_table = re.name_table();

    let opt_m = re.exec(subject);
    let m = match opt_m {
        None => {
            println!("No match");
            os::set_exit_status(1);
            return;
        }
        Some(m) => m
    };
    print_match(&m, &name_table);

    if find_all {
        let mut start_offset = m.group_end(0);
        loop {
            let opt_m = re.exec_from(subject, start_offset);
            let m = match opt_m {
                None => {
                    println!("\nNo more matches");
                    return;
                }
                Some(m) => m
            };

            println!("");
            print_match(&m, &name_table);

            start_offset = m.group_end(0);
        }
    }
}
<commit_msg>Write error messages to stderr<commit_after>// Copyright 2013 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// This is a port of the pcre project's `pcredemo` sample using rust-pcre bindings.

extern mod extra;
extern mod pcre;

use extra::enum_set::{EnumSet};
use extra::getopts::{Opt, getopts, optflag};
use extra::treemap::{TreeMap};
use pcre::{CompileOption, Match, Pcre, pcre_version};
use std::io::stdio::stderr;
use std::os;

fn print_usage(program: &str, opts: &[Opt]) {
    drop(opts);
    println!("Usage: {} [options] pattern subject", program);
    println!("Options:");
    println!("    -g                  Find all matches");
    println!("    -h, --help          Print usage and exit");
    println!("    --version           Print version information and exit");
}

fn print_version_info() {
    println!("rust-pcre 0.1 compiled against libpcre {}", pcre_version());
}

fn print_match(m: &Match, name_table: &TreeMap<~str, ~[uint]>) {
    println!("Match succeeded at offset {:u}", m.group_start(0u));

    // Show captured substrings by number.
    let mut i = 0u;
    while i < m.string_count() {
        println!("{:2u}: {:s}", i, m.group(i));
        i += 1;
    }

    let name_count = name_table.len();
    if name_count <= 0 {
        println!("No named substrings");
    } else {
        println!("Named substrings:");
        for (name, n_vec) in name_table.iter() {
            for n in n_vec.iter() {
                println!("({:u}) {:s}: {:s}", *n, *name, m.group(*n));
            }
        }
    }
}

fn main() {
    let args = os::args();
    let program = args[0].clone();

    let opts = ~[
        optflag("g"),
        optflag("h"),
        optflag("help"),
        optflag("version")
    ];

    let opt_matches = match getopts(args.tail(), opts) {
        Ok(m)  => m,
        Err(f) => {
            stderr().write_line(format!("Error: {}", f.to_err_msg()));
            os::set_exit_status(1);
            return;
        }
    };

    if opt_matches.opt_present("h") || opt_matches.opt_present("help") {
        print_usage(program, opts);
        return;
    }

    if opt_matches.opt_present("version") {
        print_version_info();
        return;
    }

    let find_all = opt_matches.opt_present("g");
    if opt_matches.free.len() == 0 {
        stderr().write_line("Error: No pattern");
        os::set_exit_status(1);
        return;
    } else if opt_matches.free.len() == 1 {
        stderr().write_line("Error: No subject");
        os::set_exit_status(1);
        return;
    } else if opt_matches.free.len() > 2 {
        stderr().write_line("Error: Too many command line arguments");
        os::set_exit_status(1);
        return;
    }

    let pattern = opt_matches.free[0].clone();
    let subject = opt_matches.free[1].clone();

    let mut compile_options: EnumSet<CompileOption> = EnumSet::empty();
    compile_options.add(pcre::DupNames);
    let re = match Pcre::compile_with_options(pattern, &compile_options) {
        Err(err) => {
            stderr().write_line(format!("Error: The pattern could not be compiled: {:s}", err.to_str()));
            os::set_exit_status(1);
            return;
        },
        Ok(re) => re
    };
    let name_table = re.name_table();

    let opt_m = re.exec(subject);
    let m = match opt_m {
        None => {
            println!("No match");
            os::set_exit_status(1);
            return;
        }
        Some(m) => m
    };
    print_match(&m, &name_table);

    if find_all {
        let mut start_offset = m.group_end(0);
        loop {
            let opt_m = re.exec_from(subject, start_offset);
            let m = match opt_m {
                None => {
                    println!("\nNo more matches");
                    return;
                }
                Some(m) => m
            };

            println!("");
            print_match(&m, &name_table);

            start_offset = m.group_end(0);
        }
    }
}
<|endoftext|>


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

//! Providers
//!
//! These are the providers which Afterburn knows how to retrieve metadata
//! from. Internally, they handle the ins and outs of each providers metadata
//! services, and externally, they provide a function to fetch that metadata in
//! a regular format.
//!
//! To add a provider, put a `pub mod provider;` line in this file, export a
//! function to fetch the metadata, and then add a match line in the top-level
//! `fetch_metadata()` function in metadata.rs.

pub mod aws;
pub mod azure;
pub mod cloudstack;
pub mod digitalocean;
pub mod gcp;
pub mod openstack;
pub mod packet;
pub mod vagrant_virtualbox;

use std::collections::HashMap;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;

use openssh_keys::PublicKey;
use users::{self, User};

use crate::errors::*;
use crate::network;

#[cfg(not(feature = "cl-legacy"))]
const ENV_PREFIX: &str = "AFTERBURN_";
#[cfg(feature = "cl-legacy")]
const ENV_PREFIX: &str = "COREOS_";

fn create_file(filename: &str) -> Result<File> {
    let file_path = Path::new(&filename);
    // create the directories if they don't exist
    let folder = file_path
        .parent()
        .ok_or_else(|| format!("could not get parent directory of {:?}", file_path))?;
    fs::create_dir_all(&folder).chain_err(|| format!("failed to create directory {:?}", folder))?;
    // create (or truncate) the file we want to write to
    File::create(file_path).chain_err(|| format!("failed to create file {:?}", file_path))
}

#[cfg(feature = "cl-legacy")]
fn write_ssh_keys(user: User, ssh_keys: Vec<PublicKey>) -> Result<()> {
    use update_ssh_keys::{AuthorizedKeyEntry, AuthorizedKeys};

    // If we don't have any SSH keys, don't bother trying to write them as
    // update-ssh-keys will yell at us.
    if !ssh_keys.is_empty() {
        // open the user's authorized keys directory
        let user_name = user.name().to_string_lossy().into_owned();
        let mut authorized_keys_dir = AuthorizedKeys::open(user, true, None).chain_err(|| {
            format!(
                "failed to open authorized keys directory for user '{}'",
                user_name
            )
        })?;

        // add the ssh keys to the directory
        let entries = ssh_keys
            .into_iter()
            .map(|key| AuthorizedKeyEntry::Valid { key })
            .collect::<Vec<_>>();
        // legacy name for legacy mode
        authorized_keys_dir.add_keys("coreos-metadata", entries, true, true)?;

        // write the changes and sync the directory
        authorized_keys_dir
            .write()
            .chain_err(|| "failed to update authorized keys directory")?;
        authorized_keys_dir
            .sync()
            .chain_err(|| "failed to update authorized keys")?;
    }

    Ok(())
}

#[cfg(not(feature = "cl-legacy"))]
fn write_ssh_keys(user: User, ssh_keys: Vec<PublicKey>) -> Result<()> {
    use std::io::ErrorKind::NotFound;
    use tempfile;
    use users::os::unix::UserExt;

    // switch users
    let _guard = users::switch::switch_user_group(user.uid(), user.primary_group_id())
        .chain_err(|| "failed to switch user/group")?;

    // get paths
    let dir_path = user.home_dir().join(".ssh").join("authorized_keys.d");
    let file_name = "afterburn";
    let file_path = &dir_path.join(file_name);

    if !ssh_keys.is_empty() {
        // ensure directory exists
        fs::create_dir_all(&dir_path)
            .chain_err(|| format!("failed to create directory {:?}", &dir_path))?;

        // create temporary file
        let mut temp_file = tempfile::Builder::new()
            .prefix(&format!(".{}-", file_name))
            .tempfile_in(&dir_path)
            .chain_err(|| "failed to create temporary file")?;

        // write out keys
        for key in ssh_keys {
            writeln!(temp_file, "{}", key).chain_err(|| {
                format!("failed to write to file {:?}", temp_file.path().display())
            })?;
        }

        // sync to disk
        temp_file
            .as_file()
            .sync_all()
            .chain_err(|| format!("failed to sync file {:?}", temp_file.path().display()))?;

        // atomically rename to destination
        // don't leak temporary file on error
        temp_file
            .persist(&file_path)
            .map_err(|e| {
                e.file.close().ok();
                e.error
            })
            .chain_err(|| format!("failed to persist file {:?}", file_path.display()))?;
    } else {
        // delete the file
        match fs::remove_file(&file_path) {
            Err(ref e) if e.kind() == NotFound => Ok(()),
            other => other,
        }
        .chain_err(|| format!("failed to remove file {:?}", file_path.display()))?;
    }

    // sync parent dir to persist updates
    let dir_file = File::open(&dir_path)
        .chain_err(|| format!("failed to open {:?} for syncing", dir_path.display()))?;
    dir_file
        .sync_all()
        .chain_err(|| format!("failed to sync {:?}", dir_path.display()))?;

    // make clippy happy while fulfilling our interface
    drop(user);

    Ok(())
}

pub trait MetadataProvider {
    fn attributes(&self) -> Result<HashMap<String, String>>;
    fn hostname(&self) -> Result<Option<String>>;
    fn ssh_keys(&self) -> Result<Vec<PublicKey>>;
    fn networks(&self) -> Result<Vec<network::Interface>>;
    fn network_devices(&self) -> Result<Vec<network::Device>>;
    fn boot_checkin(&self) -> Result<()>;

    fn write_attributes(&self, attributes_file_path: String) -> Result<()> {
        let mut attributes_file = create_file(&attributes_file_path)?;
        for (k, v) in self.attributes()? {
            writeln!(&mut attributes_file, "{}{}={}", ENV_PREFIX, k, v).chain_err(|| {
                format!("failed to write attributes to file {:?}", attributes_file)
            })?;
        }
        Ok(())
    }

    fn write_ssh_keys(&self, ssh_keys_user: String) -> Result<()> {
        let ssh_keys = self.ssh_keys()?;
        let user = users::get_user_by_name(&ssh_keys_user)
            .ok_or_else(|| format!("could not find user with username {:?}", ssh_keys_user))?;

        write_ssh_keys(user, ssh_keys)?;

        Ok(())
    }

    fn write_hostname(&self, hostname_file_path: String) -> Result<()> {
        match self.hostname()? {
            Some(ref hostname) => {
                let mut hostname_file = create_file(&hostname_file_path)?;
                writeln!(&mut hostname_file, "{}", hostname).chain_err(|| {
                    format!(
                        "failed to write hostname {:?} to file {:?}",
                        hostname, hostname_file
                    )
                })
            }
            None => Ok(()),
        }
    }

    fn write_network_units(&self, network_units_dir: String) -> Result<()> {
        let dir_path = Path::new(&network_units_dir);
        fs::create_dir_all(&dir_path)
            .chain_err(|| format!("failed to create directory {:?}", dir_path))?;
        for interface in &self.networks()? {
            let file_path = dir_path.join(interface.unit_name());
            let mut unit_file = File::create(&file_path)
                .chain_err(|| format!("failed to create file {:?}", file_path))?;
            write!(&mut unit_file, "{}", interface.config()).chain_err(|| {
                format!(
                    "failed to write network interface unit file {:?}",
                    unit_file
                )
            })?;
        }
        for device in &self.network_devices()? {
            let file_path = dir_path.join(device.unit_name());
            let mut unit_file = File::create(&file_path)
                .chain_err(|| format!("failed to create file {:?}", file_path))?;
            write!(&mut unit_file, "{}", device.config()).chain_err(|| {
                format!("failed to write network device unit file {:?}", unit_file)
            })?;
        }
        Ok(())
    }
}
<commit_msg>providers: remove unused import<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Providers
//!
//! These are the providers which Afterburn knows how to retrieve metadata
//! from. Internally, they handle the ins and outs of each providers metadata
//! services, and externally, they provide a function to fetch that metadata in
//! a regular format.
//!
//! To add a provider, put a `pub mod provider;` line in this file, export a
//! function to fetch the metadata, and then add a match line in the top-level
//! `fetch_metadata()` function in metadata.rs.

pub mod aws;
pub mod azure;
pub mod cloudstack;
pub mod digitalocean;
pub mod gcp;
pub mod openstack;
pub mod packet;
pub mod vagrant_virtualbox;

use std::collections::HashMap;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;

use openssh_keys::PublicKey;
use users::{self, User};

use crate::errors::*;
use crate::network;

#[cfg(not(feature = "cl-legacy"))]
const ENV_PREFIX: &str = "AFTERBURN_";
#[cfg(feature = "cl-legacy")]
const ENV_PREFIX: &str = "COREOS_";

fn create_file(filename: &str) -> Result<File> {
    let file_path = Path::new(&filename);
    // create the directories if they don't exist
    let folder = file_path
        .parent()
        .ok_or_else(|| format!("could not get parent directory of {:?}", file_path))?;
    fs::create_dir_all(&folder).chain_err(|| format!("failed to create directory {:?}", folder))?;
    // create (or truncate) the file we want to write to
    File::create(file_path).chain_err(|| format!("failed to create file {:?}", file_path))
}

#[cfg(feature = "cl-legacy")]
fn write_ssh_keys(user: User, ssh_keys: Vec<PublicKey>) -> Result<()> {
    use update_ssh_keys::{AuthorizedKeyEntry, AuthorizedKeys};

    // If we don't have any SSH keys, don't bother trying to write them as
    // update-ssh-keys will yell at us.
    if !ssh_keys.is_empty() {
        // open the user's authorized keys directory
        let user_name = user.name().to_string_lossy().into_owned();
        let mut authorized_keys_dir = AuthorizedKeys::open(user, true, None).chain_err(|| {
            format!(
                "failed to open authorized keys directory for user '{}'",
                user_name
            )
        })?;

        // add the ssh keys to the directory
        let entries = ssh_keys
            .into_iter()
            .map(|key| AuthorizedKeyEntry::Valid { key })
            .collect::<Vec<_>>();
        // legacy name for legacy mode
        authorized_keys_dir.add_keys("coreos-metadata", entries, true, true)?;

        // write the changes and sync the directory
        authorized_keys_dir
            .write()
            .chain_err(|| "failed to update authorized keys directory")?;
        authorized_keys_dir
            .sync()
            .chain_err(|| "failed to update authorized keys")?;
    }

    Ok(())
}

#[cfg(not(feature = "cl-legacy"))]
fn write_ssh_keys(user: User, ssh_keys: Vec<PublicKey>) -> Result<()> {
    use std::io::ErrorKind::NotFound;
    use users::os::unix::UserExt;

    // switch users
    let _guard = users::switch::switch_user_group(user.uid(), user.primary_group_id())
        .chain_err(|| "failed to switch user/group")?;

    // get paths
    let dir_path = user.home_dir().join(".ssh").join("authorized_keys.d");
    let file_name = "afterburn";
    let file_path = &dir_path.join(file_name);

    if !ssh_keys.is_empty() {
        // ensure directory exists
        fs::create_dir_all(&dir_path)
            .chain_err(|| format!("failed to create directory {:?}", &dir_path))?;

        // create temporary file
        let mut temp_file = tempfile::Builder::new()
            .prefix(&format!(".{}-", file_name))
            .tempfile_in(&dir_path)
            .chain_err(|| "failed to create temporary file")?;

        // write out keys
        for key in ssh_keys {
            writeln!(temp_file, "{}", key).chain_err(|| {
                format!("failed to write to file {:?}", temp_file.path().display())
            })?;
        }

        // sync to disk
        temp_file
            .as_file()
            .sync_all()
            .chain_err(|| format!("failed to sync file {:?}", temp_file.path().display()))?;

        // atomically rename to destination
        // don't leak temporary file on error
        temp_file
            .persist(&file_path)
            .map_err(|e| {
                e.file.close().ok();
                e.error
            })
            .chain_err(|| format!("failed to persist file {:?}", file_path.display()))?;
    } else {
        // delete the file
        match fs::remove_file(&file_path) {
            Err(ref e) if e.kind() == NotFound => Ok(()),
            other => other,
        }
        .chain_err(|| format!("failed to remove file {:?}", file_path.display()))?;
    }

    // sync parent dir to persist updates
    let dir_file = File::open(&dir_path)
        .chain_err(|| format!("failed to open {:?} for syncing", dir_path.display()))?;
    dir_file
        .sync_all()
        .chain_err(|| format!("failed to sync {:?}", dir_path.display()))?;

    // make clippy happy while fulfilling our interface
    drop(user);

    Ok(())
}

pub trait MetadataProvider {
    fn attributes(&self) -> Result<HashMap<String, String>>;
    fn hostname(&self) -> Result<Option<String>>;
    fn ssh_keys(&self) -> Result<Vec<PublicKey>>;
    fn networks(&self) -> Result<Vec<network::Interface>>;
    fn network_devices(&self) -> Result<Vec<network::Device>>;
    fn boot_checkin(&self) -> Result<()>;

    fn write_attributes(&self, attributes_file_path: String) -> Result<()> {
        let mut attributes_file = create_file(&attributes_file_path)?;
        for (k, v) in self.attributes()? {
            writeln!(&mut attributes_file, "{}{}={}", ENV_PREFIX, k, v).chain_err(|| {
                format!("failed to write attributes to file {:?}", attributes_file)
            })?;
        }
        Ok(())
    }

    fn write_ssh_keys(&self, ssh_keys_user: String) -> Result<()> {
        let ssh_keys = self.ssh_keys()?;
        let user = users::get_user_by_name(&ssh_keys_user)
            .ok_or_else(|| format!("could not find user with username {:?}", ssh_keys_user))?;

        write_ssh_keys(user, ssh_keys)?;

        Ok(())
    }

    fn write_hostname(&self, hostname_file_path: String) -> Result<()> {
        match self.hostname()? {
            Some(ref hostname) => {
                let mut hostname_file = create_file(&hostname_file_path)?;
                writeln!(&mut hostname_file, "{}", hostname).chain_err(|| {
                    format!(
                        "failed to write hostname {:?} to file {:?}",
                        hostname, hostname_file
                    )
                })
            }
            None => Ok(()),
        }
    }

    fn write_network_units(&self, network_units_dir: String) -> Result<()> {
        let dir_path = Path::new(&network_units_dir);
        fs::create_dir_all(&dir_path)
            .chain_err(|| format!("failed to create directory {:?}", dir_path))?;
        for interface in &self.networks()? {
            let file_path = dir_path.join(interface.unit_name());
            let mut unit_file = File::create(&file_path)
                .chain_err(|| format!("failed to create file {:?}", file_path))?;
            write!(&mut unit_file, "{}", interface.config()).chain_err(|| {
                format!(
                    "failed to write network interface unit file {:?}",
                    unit_file
                )
            })?;
        }
        for device in &self.network_devices()? {
            let file_path = dir_path.join(device.unit_name());
            let mut unit_file = File::create(&file_path)
                .chain_err(|| format!("failed to create file {:?}", file_path))?;
            write!(&mut unit_file, "{}", device.config()).chain_err(|| {
                format!("failed to write network device unit file {:?}", unit_file)
            })?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Send records as forward mode.
//!
//! ## Usage
//!
//! This trait is used as follows:
//!
//! ```no_run
//! extern crate fruently;
//! use fruently::fluent::Fluent;
//! use std::collections::HashMap;
//! use fruently::forwardable::Forwardable;
//!
//! fn main() {
//!     let fruently = Fluent::new("0.0.0.0:24224", "test");
//!     let mut obj1: HashMap<String, String> = HashMap::new();
//!     obj1.insert("hey".to_string(), "Rust with forward mode!".to_string());
//!     let mut obj2: HashMap<String, String> = HashMap::new();
//!     obj2.insert("yeah".to_string(), "Also sent together!".to_string());
//!     // In practice, use time::now() or chrono crate's methods instead.
//!     let time = 1462080486;
//!     let entry = (time, obj1);
//!     let entry2 = (time, obj2);
//!     let _ = fruently.post(vec![(entry), (entry2)]);
//! }
//! ```

use std::net::ToSocketAddrs;
use rustc_serialize::Encodable;
use retry::retry_exponentially;
use record::FluentError;
use forwardable::Forwardable;
use forwardable::Entry;
use fluent::Fluent;

#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct Forward<T: Encodable> {
    tag: String,
    entries: Vec<Entry<T>>,
}

impl<T: Encodable> Forward<T> {
    pub fn new(tag: String, entries: Vec<Entry<T>>) -> Forward<T> {
        Forward {
            tag: tag,
            entries: entries,
        }
    }
}

impl<A: ToSocketAddrs> Forwardable for Fluent<A> {
    /// Post record into Fluentd. With time version.
    fn post<T>(self, entries: Vec<Entry<T>>) -> Result<(), FluentError>
        where T: Encodable
    {
        let forward = Forward::new(self.get_tag(), entries);
        let addr = self.get_addr();
        let (max, multiplier) = self.get_conf().build();
        match retry_exponentially(max,
                                  multiplier,
                                  || Fluent::closure_send_as_forward(addr, &forward),
                                  |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
#[cfg(feature="fluentd")]
mod tests {
    use time;
    use fluent::Fluent;

    #[test]
    fn test_post() {
        use std::collections::HashMap;
        use forwardable::Forwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj1: HashMap<String, String> = HashMap::new();
        obj1.insert("hey".to_string(), "Rust with forward mode!".to_string());
        let mut obj2: HashMap<String, String> = HashMap::new();
        obj2.insert("yeah".to_string(), "Also sent together!".to_string());
        let time = time::now().to_timespec().sec;
        let entry = (time, obj1);
        let entry2 = (time, obj2);
        let result = fruently.post(vec![(entry), (entry2)]).is_ok();
        assert_eq!(true, result);
    }
}
<commit_msg>forward: Use time crate in doctest<commit_after>//! Send records as forward mode.
//!
//! ## Usage
//!
//! This trait is used as follows:
//!
//! ```no_run
//! extern crate fruently;
//! extern crate time;
//! use fruently::fluent::Fluent;
//! use std::collections::HashMap;
//! use fruently::forwardable::Forwardable;
//!
//! fn main() {
//!     let fruently = Fluent::new("0.0.0.0:24224", "test");
//!     let mut obj1: HashMap<String, String> = HashMap::new();
//!     obj1.insert("hey".to_string(), "Rust with forward mode!".to_string());
//!     let mut obj2: HashMap<String, String> = HashMap::new();
//!     obj2.insert("yeah".to_string(), "Also sent together!".to_string());
//!     let time = time::now().to_timespec().sec;
//!     let entry = (time, obj1);
//!     let entry2 = (time, obj2);
//!     let _ = fruently.post(vec![(entry), (entry2)]);
//! }
//! ```

use std::net::ToSocketAddrs;
use rustc_serialize::Encodable;
use retry::retry_exponentially;
use record::FluentError;
use forwardable::Forwardable;
use forwardable::Entry;
use fluent::Fluent;

#[derive(Debug, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub struct Forward<T: Encodable> {
    tag: String,
    entries: Vec<Entry<T>>,
}

impl<T: Encodable> Forward<T> {
    pub fn new(tag: String, entries: Vec<Entry<T>>) -> Forward<T> {
        Forward {
            tag: tag,
            entries: entries,
        }
    }
}

impl<A: ToSocketAddrs> Forwardable for Fluent<A> {
    /// Post record into Fluentd. With time version.
    fn post<T>(self, entries: Vec<Entry<T>>) -> Result<(), FluentError>
        where T: Encodable
    {
        let forward = Forward::new(self.get_tag(), entries);
        let addr = self.get_addr();
        let (max, multiplier) = self.get_conf().build();
        match retry_exponentially(max,
                                  multiplier,
                                  || Fluent::closure_send_as_forward(addr, &forward),
                                  |response| response.is_ok()) {
            Ok(_) => Ok(()),
            Err(v) => Err(From::from(v)),
        }
    }
}

#[cfg(test)]
#[cfg(feature="fluentd")]
mod tests {
    use time;
    use fluent::Fluent;

    #[test]
    fn test_post() {
        use std::collections::HashMap;
        use forwardable::Forwardable;

        let fruently = Fluent::new("0.0.0.0:24224", "test");
        let mut obj1: HashMap<String, String> = HashMap::new();
        obj1.insert("hey".to_string(), "Rust with forward mode!".to_string());
        let mut obj2: HashMap<String, String> = HashMap::new();
        obj2.insert("yeah".to_string(), "Also sent together!".to_string());
        let time = time::now().to_timespec().sec;
        let entry = (time, obj1);
        let entry2 = (time, obj2);
        let result = fruently.post(vec![(entry), (entry2)]).is_ok();
        assert_eq!(true, result);
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;

use std;
use std::io::Write;
use self::byteorder::NativeEndian;
use self::byteorder::WriteBytesExt;

/// The remainder of the
pub trait Value {

    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &Self ) -> usize;

    /// Gets a zero.
    fn zero() -> Self;

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize;

    /// Converts the number of buckets into the value type.
    fn from_bucket_count( bucket_count: &usize ) -> Self;

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> Self;

    /// Converts the given index into the value type.
    fn from_index( index: usize ) -> Self;

    /// Decrements the value by one.
    fn decrement( &self ) -> Self;

    /// Serializes the value.
    fn serialize(
        &self,
        &mut Write
    ) -> Result<(), std::io::Error>;
}

/// Implements value trait for i32
impl Value for i32
{
    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &i32 ) -> usize {
        return ( self.clone() as usize ) % ( buckets.clone() as usize ) ;
    }

    /// Gets a zero.
    fn zero() -> i32 { return 0; }

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize { return self.clone() as usize; }

    /// Converts the specified value to a value that can be stored in the container.
    fn from_bucket_count( bucket_count: &usize ) -> i32 { return bucket_count.clone() as i32; }

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> i32 { return member_count as i32; }

    /// Converts the given value to index.
    fn from_index( index: usize ) -> i32 { return index as i32; }

    /// Decrements the value by one.
    fn decrement( &self ) -> i32 { return self - 1; }

    /// Serializes the value.
    fn serialize(
        &self,
        writer: &mut Write
    ) -> Result<(), std::io::Error>
    {
        writer.write_i32::<NativeEndian>( *self )?;
        Ok(())
    }
}

/// The index of the number of members in the set.
const SIZE_INDEX: usize = 1;

/// The index of the first bucket.
const FIRST_BUCKET_INDEX: usize = 2;

/// Defines how the data is stored in the scalar set.
 enum Storage<'a, TA, TB>
    where TB: 'a {

    /// The data is stored as a vector.
    Vector { data: Vec<TA> },

    /// The data is stored as a slice.
    Slice { data: &'a[TB] }
 }

pub struct RoScalarSet<'a, T>
where T: std::cmp::Ord + std::clone::Clone + Value + 'a {
    _storage: Storage<'a, T, T>
}

impl<'a, T> RoScalarSet<'a, T>
    where T: std::cmp::Ord + std::clone::Clone + Value + 'a {

    /// Returns a new integer hash set holding the specified values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn new<'b, 'c> (
            values: &'c[T]
    ) -> RoScalarSet<T> {

        // Determine the number of buckets. We introduce a 5% overhead.
        let bucket_count: usize = ( values.len() as f64 * 0.05 ).ceil() as usize;
        let mut storage: Vec<T> = vec!( T::zero(); ( FIRST_BUCKET_INDEX + bucket_count + 1 + values.len() ) );

        // Store the number of buckets.
        let buckets = T::from_bucket_count( &bucket_count );
        storage[ 0 ] = buckets.clone();

        // Store the number of members.
        storage[ SIZE_INDEX ] = T::from_member_count( values.len() );

        // Count the values required for each bucket.
        let mut values_in_buckets: Vec<i32> = vec!( 0; bucket_count );
        for v in values {
            let bucket = v.get_bucket_index( &buckets );
            values_in_buckets[ bucket ] += 1;
        }

        // Set bucket pointers to point the end of each bucket.
        // They will be decrements one-by-one when the buckets are filled.
        let first_bucket: usize = FIRST_BUCKET_INDEX;
        let data_start: usize = FIRST_BUCKET_INDEX + bucket_count + 1;
        let mut previous_bucket_end = data_start;
        for b in 0..bucket_count  {

            // The end of the previous bucket is the start of the previous bucket.
            let index = previous_bucket_end + values_in_buckets[ b ].as_index();
            storage[ b + first_bucket ] = T::from_index( index );
            previous_bucket_end = index;
        }

        // Fix the end of the last bucket.
        storage[ first_bucket + bucket_count ] = T::from_index( storage.len() );

        // Put values into buckets.
        for v in values {

            // Determine bucket for the value.
            let bucket_id = v.get_bucket_index( &buckets );

            // Make room for the new value.
            storage[ bucket_id + first_bucket ] = storage[ bucket_id + first_bucket ].decrement();
            let value_index: usize = storage[ bucket_id + first_bucket ].as_index();
            storage[ value_index ] = v.clone();
        }

        // Sort each bucket to enable binary search.
        for b in 0..bucket_count  {

            // Determine the location of the bucket.
            let begin: usize = storage[ b + first_bucket ].as_index();
            let end: usize = storage[ b + first_bucket + 1 ].as_index();
            if end < begin {
                panic!( "Invalid bucket: {}", b );
            }

            // Get a splice for sorting.
            let ( _, remainder ) =  storage.split_at_mut( begin );
            let ( bucket,  _ )  = remainder.split_at_mut( end - begin );
            bucket.sort();
        }

        let storage: Storage<T, T> = Storage::Vector { data: storage };
        return RoScalarSet { _storage: storage  };
    }

    /// Attaches an integer hash set to a slice holding the values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn attach<'b> (
            buffer: &'b[T]
    ) -> Result< ( RoScalarSet<'b, T>, &'b[T] ), &str > {

        // Determine the lenght of this scalar set.
        if buffer.len() < 4 {
            return Err( "The buffer is to small" );
        }
        let buckets = buffer[0].as_index();
        let values = buffer[SIZE_INDEX].as_index();
        let total_size = FIRST_BUCKET_INDEX + ( buckets + 1 ) + values;

        // Attach.
        let ( set, remainder ) = buffer.split_at( total_size );
        let storage: Storage<T, T> = Storage::Slice { data: set };
        return Ok( ( RoScalarSet { _storage: storage  }, remainder ) );
    }

    /// Checks whether the given value exists in the set or not.
    pub fn contains(
        &self,
        value: T
    ) -> bool {

        // Get the bucket associated with the value.
        let bucket = self.get_bucket( &value );

        // Locate the value.
        match bucket.binary_search( &value ) {
            Ok( _ ) => return true,
            Err(_) => return false,
        }
    }

    /// Gets the number of members in the set.
    pub fn size(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ SIZE_INDEX ].as_index();
    }

    /// Gets the number of buckets.
    pub fn bucket_count(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ 0 ].as_index();
    }

    /// Serializes the scalar set into the given writer.
    pub fn serialize<W>(
        &self,
        writer: &mut W
    ) -> Result<(), std::io::Error>
    where W: Write {

        // Write our intern
        let storage = self.borrow_storage();
        for v in storage {
            v.serialize( writer )?;
        }
        Ok(())
    }

    /// Gets a read-only slice containing the values of a bucket.
    fn get_bucket(
        &self,
        value: &T
    ) -> &[T] {

        // Determine the bucket.
        let storage = self.borrow_storage();
        let bucket_id: usize = value.get_bucket_index( &storage[ 0 ] );
        let bucket_index = bucket_id + FIRST_BUCKET_INDEX;
        let begin: usize = storage[ bucket_index ].as_index();
        let end: usize = storage[ ( bucket_index + 1 ) ].as_index();
        let  ( _, remainder ) = storage.split_at( begin );
        let  ( bucket, _ )  = remainder.split_at( end - begin );
        return bucket;
    }

    /// Borrows the storage for accessing the values.
    fn borrow_storage(
        &'a self
    ) -> &'a [T] {
        let s: &'a [T] = match &self._storage {
            &Storage::Vector { ref data } => data.as_slice(),
            &Storage::Slice { ref data } => data,

        };
        return s;
    }
}
<commit_msg>Avoid binding the lifetime of input values and new scalar set<commit_after>extern crate byteorder;

use std;
use std::io::Write;
use self::byteorder::NativeEndian;
use self::byteorder::WriteBytesExt;

/// The remainder of the
pub trait Value {

    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &Self ) -> usize;

    /// Gets a zero.
    fn zero() -> Self;

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize;

    /// Converts the number of buckets into the value type.
    fn from_bucket_count( bucket_count: &usize ) -> Self;

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> Self;

    /// Converts the given index into the value type.
    fn from_index( index: usize ) -> Self;

    /// Decrements the value by one.
    fn decrement( &self ) -> Self;

    /// Serializes the value.
    fn serialize(
        &self,
        &mut Write
    ) -> Result<(), std::io::Error>;
}

/// Implements value trait for i32
impl Value for i32
{
    /// Gets the index of the bucket for this value.
    fn get_bucket_index( &self, buckets: &i32 ) -> usize {
        return ( self.clone() as usize ) % ( buckets.clone() as usize ) ;
    }

    /// Gets a zero.
    fn zero() -> i32 { return 0; }

    /// Gets the integer value as a size.
    fn as_index( &self ) -> usize { return self.clone() as usize; }

    /// Converts the specified value to a value that can be stored in the container.
    fn from_bucket_count( bucket_count: &usize ) -> i32 { return bucket_count.clone() as i32; }

    /// Converts the number of set members into the value type.
    fn from_member_count( member_count: usize ) -> i32 { return member_count as i32; }

    /// Converts the given value to index.
    fn from_index( index: usize ) -> i32 { return index as i32; }

    /// Decrements the value by one.
    fn decrement( &self ) -> i32 { return self - 1; }

    /// Serializes the value.
    fn serialize(
        &self,
        writer: &mut Write
    ) -> Result<(), std::io::Error>
    {
        writer.write_i32::<NativeEndian>( *self )?;
        Ok(())
    }
}

/// The index of the number of members in the set.
const SIZE_INDEX: usize = 1;

/// The index of the first bucket.
const FIRST_BUCKET_INDEX: usize = 2;

/// Defines how the data is stored in the scalar set.
 enum Storage<'a, TA, TB>
    where TB: 'a {

    /// The data is stored as a vector.
    Vector { data: Vec<TA> },

    /// The data is stored as a slice.
    Slice { data: &'a[TB] }
 }

pub struct RoScalarSet<'a, T>
where T: std::cmp::Ord + std::clone::Clone + Value + 'a {
    _storage: Storage<'a, T, T>
}

impl<'a, T> RoScalarSet<'a, T>
    where T: std::cmp::Ord + std::clone::Clone + Value + 'a {

    /// Returns a new integer hash set holding the specified values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn new<'b, 'c> (
            values: &'c[T]
    ) -> RoScalarSet<'b,T> {

        // Determine the number of buckets. We introduce a 5% overhead.
        let bucket_count: usize = ( values.len() as f64 * 0.05 ).ceil() as usize;
        let mut storage: Vec<T> = vec!( T::zero(); ( FIRST_BUCKET_INDEX + bucket_count + 1 + values.len() ) );

        // Store the number of buckets.
        let buckets = T::from_bucket_count( &bucket_count );
        storage[ 0 ] = buckets.clone();

        // Store the number of members.
        storage[ SIZE_INDEX ] = T::from_member_count( values.len() );

        // Count the values required for each bucket.
        let mut values_in_buckets: Vec<i32> = vec!( 0; bucket_count );
        for v in values {
            let bucket = v.get_bucket_index( &buckets );
            values_in_buckets[ bucket ] += 1;
        }

        // Set bucket pointers to point the end of each bucket.
        // They will be decrements one-by-one when the buckets are filled.
        let first_bucket: usize = FIRST_BUCKET_INDEX;
        let data_start: usize = FIRST_BUCKET_INDEX + bucket_count + 1;
        let mut previous_bucket_end = data_start;
        for b in 0..bucket_count  {

            // The end of the previous bucket is the start of the previous bucket.
            let index = previous_bucket_end + values_in_buckets[ b ].as_index();
            storage[ b + first_bucket ] = T::from_index( index );
            previous_bucket_end = index;
        }

        // Fix the end of the last bucket.
        storage[ first_bucket + bucket_count ] = T::from_index( storage.len() );

        // Put values into buckets.
        for v in values {

            // Determine bucket for the value.
            let bucket_id = v.get_bucket_index( &buckets );

            // Make room for the new value.
            storage[ bucket_id + first_bucket ] = storage[ bucket_id + first_bucket ].decrement();
            let value_index: usize = storage[ bucket_id + first_bucket ].as_index();
            storage[ value_index ] = v.clone();
        }

        // Sort each bucket to enable binary search.
        for b in 0..bucket_count  {

            // Determine the location of the bucket.
            let begin: usize = storage[ b + first_bucket ].as_index();
            let end: usize = storage[ b + first_bucket + 1 ].as_index();
            if end < begin {
                panic!( "Invalid bucket: {}", b );
            }

            // Get a splice for sorting.
            let ( _, remainder ) =  storage.split_at_mut( begin );
            let ( bucket,  _ )  = remainder.split_at_mut( end - begin );
            bucket.sort();
        }

        let storage: Storage<'b, T, T> = Storage::Vector { data: storage };
        return RoScalarSet { _storage: storage  };
    }

    /// Attaches an integer hash set to a slice holding the values.
    ///
    /// # ArgumentRoScalarSets
    ///
    /// * 'values' Holds the values stored in the hash set.
    pub fn attach<'b> (
            buffer: &'b[T]
    ) -> Result< ( RoScalarSet<'b, T>, &'b[T] ), &str > {

        // Determine the lenght of this scalar set.
        if buffer.len() < 4 {
            return Err( "The buffer is to small" );
        }
        let buckets = buffer[0].as_index();
        let values = buffer[SIZE_INDEX].as_index();
        let total_size = FIRST_BUCKET_INDEX + ( buckets + 1 ) + values;

        // Attach.
        let ( set, remainder ) = buffer.split_at( total_size );
        let storage: Storage<T, T> = Storage::Slice { data: set };
        return Ok( ( RoScalarSet { _storage: storage  }, remainder ) );
    }

    /// Checks whether the given value exists in the set or not.
    pub fn contains(
        &self,
        value: T
    ) -> bool {

        // Get the bucket associated with the value.
        let bucket = self.get_bucket( &value );

        // Locate the value.
        match bucket.binary_search( &value ) {
            Ok( _ ) => return true,
            Err(_) => return false,
        }
    }

    /// Gets the number of members in the set.
    pub fn size(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ SIZE_INDEX ].as_index();
    }

    /// Gets the number of buckets.
    pub fn bucket_count(
        &self
    ) -> usize {
        let storage = self.borrow_storage();
        return storage[ 0 ].as_index();
    }

    /// Serializes the scalar set into the given writer.
    pub fn serialize<W>(
        &self,
        writer: &mut W
    ) -> Result<(), std::io::Error>
    where W: Write {

        // Write our intern
        let storage = self.borrow_storage();
        for v in storage {
            v.serialize( writer )?;
        }
        Ok(())
    }

    /// Gets a read-only slice containing the values of a bucket.
    fn get_bucket(
        &self,
        value: &T
    ) -> &[T] {

        // Determine the bucket.
        let storage = self.borrow_storage();
        let bucket_id: usize = value.get_bucket_index( &storage[ 0 ] );
        let bucket_index = bucket_id + FIRST_BUCKET_INDEX;
        let begin: usize = storage[ bucket_index ].as_index();
        let end: usize = storage[ ( bucket_index + 1 ) ].as_index();
        let  ( _, remainder ) = storage.split_at( begin );
        let  ( bucket, _ )  = remainder.split_at( end - begin );
        return bucket;
    }

    /// Borrows the storage for accessing the values.
    fn borrow_storage(
        &'a self
    ) -> &'a [T] {
        let s: &'a [T] = match &self._storage {
            &Storage::Vector { ref data } => data.as_slice(),
            &Storage::Slice { ref data } => data,

        };
        return s;
    }
}
<|endoftext|>