<commit_before>use cgmath::{Point, Point3, Vector, Vector3};
use cgmath::Aabb3;
use std::cmp::{min, max, partial_min, partial_max};
use std::sync::Mutex;
use stopwatch::TimerSet;

use common::block_position::BlockPosition;
use common::entity::EntityId;
use common::id_allocator::IdAllocator;
use common::lod::LODIndex;
use common::terrain_block;
use common::terrain_block::{TerrainBlock, tri};

use heightmap::HeightMap;
use voxel;
use voxel::{Fracu8, Fraci8, Voxel, SurfaceVoxel, Vertex, Normal};
use voxel_tree;
use voxel_tree::VoxelTree;

pub fn generate_voxel(
  timers: &TimerSet,
  heightmap: &HeightMap,
  voxel: &voxel::Bounds,
) -> Voxel
{
  timers.time("generate_voxel", || {
    let field_contains = |x, y, z| {
      heightmap.density_at(x, y, z) >= 0.0
    };

    let get_normal = |x, y, z| {
      heightmap.normal_at(0.01, x, y, z)
    };

    let size = voxel.size();
    let (x1, y1, z1) = (voxel.x as f32 * size, voxel.y as f32 * size, voxel.z as f32 * size);
    let delta = size;
    let (x2, y2, z2) = (x1 + delta, y1 + delta, z1 + delta);
    // corners[x][y][z]
    let corners = [
      [
        [ field_contains(x1, y1, z1), field_contains(x1, y1, z2) ],
        [ field_contains(x1, y2, z1), field_contains(x1, y2, z2) ],
      ],
      [
        [ field_contains(x2, y1, z1), field_contains(x2, y1, z2) ],
        [ field_contains(x2, y2, z1), field_contains(x2, y2, z2) ],
      ],
    ];

    let corner;
    let mut any_inside = false;
    let mut all_inside = true;

    {
      let mut get_corner = |x1:usize, y1:usize, z1:usize| {
        let corner = corners[x1][y1][z1];
        any_inside = any_inside || corner;
        all_inside = all_inside && corner;
        corner
      };

      corner = get_corner(0,0,0);
      let _ = get_corner(0,0,1);
      let _ = get_corner(0,1,0);
      let _ = get_corner(0,1,1);
      let _ = get_corner(1,0,0);
      let _ = get_corner(1,0,1);
      let _ = get_corner(1,1,0);
      let _ = get_corner(1,1,1);
    }

    let all_corners_same = any_inside == all_inside;
    if all_corners_same {
      return Voxel::Volume(all_inside)
    }

    let mut vertex: Vector3<u32> = Vector3::new(0, 0, 0);
    let mut n = 0;
    for (&x, corners) in [0, 0xFF].iter().zip(corners.iter()) {
    for (&y, corners) in [0, 0xFF].iter().zip(corners.iter()) {
    for (&z, &corner) in [0, 0xFF].iter().zip(corners.iter()) {
      if corner {
        vertex.add_self_v(&Vector3::new(x, y, z));
        n += 1;
      }
    }}}

    {
      // Sample in extra areas to help weight the vertex to the appropriate place.
      let mut sample_extra = |lg_s: u8| {
        let fs = 1.0 / ((1 << lg_s) as f32);
        let mfs = 1.0 - fs;
        let s = 0x100 >> lg_s;
        let ms = 0x100 - s;
        for &(wx, x) in
          [((voxel.x as f32 + fs) * size, s), ((voxel.x as f32 + mfs) * size, ms)].iter() {
        for &(wy, y) in
          [((voxel.y as f32 + fs) * size, s), ((voxel.y as f32 + mfs) * size, ms)].iter() {
        for &(wz, z) in
          [((voxel.z as f32 + fs) * size, s), ((voxel.z as f32 + mfs) * size, ms)].iter() {
          if field_contains(wx, wy, wz) {
            vertex.add_self_v(&Vector3::new(x, y, z).mul_s(lg_s as u32));
            n += lg_s as u32;
          }
        }}}
      };

      sample_extra(2);
    }

    let vertex = vertex.div_s(n);
    let vertex =
      Vertex {
        x: Fracu8::of(vertex.x as u8),
        y: Fracu8::of(vertex.y as u8),
        z: Fracu8::of(vertex.z as u8),
      };

    let normal;
    {
      // Okay, this is silly to have right after we construct the vertex.
      let vertex = vertex.to_world_vertex(voxel);
      normal = get_normal(vertex.x, vertex.y, vertex.z).mul_s(127.0);
    }

    // Okay, so we scale the normal by 127, and use 127 to represent 1.0.
    // Then we store it in a `Fraci8`, which scales by 128 and represents a
    // fraction in [0,1). That seems wrong, but this is normal data, so scaling
    // doesn't matter. Sketch factor is over 9000, but it's not wrong.

    let normal = Vector3::new(normal.x as i32, normal.y as i32, normal.z as i32);
    let normal =
      Vector3::new(
        max(-127, min(127, normal.x)) as i8,
        max(-127, min(127, normal.y)) as i8,
        max(-127, min(127, normal.z)) as i8,
      );

    let normal =
      Normal {
        x: Fraci8::of(normal.x),
        y: Fraci8::of(normal.y),
        z: Fraci8::of(normal.z),
      };

    Voxel::Surface(SurfaceVoxel {
      inner_vertex: vertex,
      normal: normal,
      corner_inside_surface: corner,
    })
  })
}

fn make_bounds(
  v1: &Point3<f32>,
  v2: &Point3<f32>,
  v3: &Point3<f32>,
) -> Aabb3<f32> {
  let minx = partial_min(v1.x, v2.x);
  let minx = minx.and_then(|m| partial_min(m, v3.x));
  let minx = minx.unwrap();

  let maxx = partial_max(v1.x, v2.x);
  let maxx = maxx.and_then(|m| partial_max(m, v3.x));
  let maxx = maxx.unwrap();

  let miny = partial_min(v1.y, v2.y);
  let miny = miny.and_then(|m| partial_min(m, v3.y));
  let miny = miny.unwrap();

  let maxy = partial_max(v1.y, v2.y);
  let maxy = maxy.and_then(|m| partial_max(m, v3.y));
  let maxy = maxy.unwrap();

  let minz = partial_min(v1.z, v2.z);
  let minz = minz.and_then(|m| partial_min(m, v3.z));
  let minz = minz.unwrap();

  let maxz = partial_max(v1.z, v2.z);
  let maxz = maxz.and_then(|m| partial_max(m, v3.z));
  let maxz = maxz.unwrap();

  Aabb3::new(
    // TODO: Remove this - 1.0. It's a temporary hack until voxel collisions work,
    // to avoid zero-height Aabb3s.
    Point3::new(minx, miny - 1.0, minz),
    Point3::new(maxx, maxy, maxz),
  )
}

/// Generate a `TerrainBlock` based on a given position in a `VoxelTree`.
/// Any necessary voxels will be generated.
pub fn generate_block(
  timers: &TimerSet,
  id_allocator: &Mutex<IdAllocator<EntityId>>,
  heightmap: &HeightMap,
  voxels: &mut VoxelTree,
  position: &BlockPosition,
  lod_index: LODIndex,
) -> TerrainBlock {
  timers.time("update.generate_block", || {
    let mut block = TerrainBlock::empty();

    let position = position.to_world_position();
    let iposition = Point3::new(position.x as i32, position.y as i32, position.z as i32);

    let lateral_samples = terrain_block::EDGE_SAMPLES[lod_index.0 as usize] as i32;
    let lg_size = terrain_block::LG_SAMPLE_SIZE[lod_index.0 as usize] as i16;

    let bounds_of = |v: &Point3<i32>| {
      voxel::Bounds::new(v.x, v.y, v.z, lg_size)
    };

    let mut get_voxel = |bounds: &voxel::Bounds| {
      let branch = voxels.get_mut_or_create(bounds);
      let r;
      match branch {
        &mut voxel_tree::TreeBody::Leaf(v) => r = v,
        &mut voxel_tree::TreeBody::Empty => {
          r = generate_voxel(timers, heightmap, bounds);
          *branch = voxel_tree::TreeBody::Leaf(r);
        },
        &mut voxel_tree::TreeBody::Branch(_) => {
          // Overwrite existing for now.
          // TODO: Don't do ^that.
          r = generate_voxel(timers, heightmap, bounds);
          *branch = voxel_tree::TreeBody::Leaf(r);
        },
      };
      r
    };

    macro_rules! get_vertex(($v:expr) => {{
      let bounds = bounds_of($v);
      let voxel;
      match get_voxel(&bounds) {
        Voxel::Surface(v) => voxel = v,
        _ => panic!("Couldn't find populated edge neighbor voxel"),
      }
      (voxel.inner_vertex.to_world_vertex(&bounds), voxel.normal.to_world_normal())
    }});

    {
      let mut add_poly =
        |v1: Point3<f32>, n1, v2: Point3<f32>, n2, center: Point3<f32>, center_normal| {
          let id = id_allocator.lock().unwrap().allocate();

          block.vertex_coordinates.push(tri(v1, v2, center));
          block.normals.push(tri(n1, n2, center_normal));
          block.ids.push(id);
          block.bounds.push((id, make_bounds(&v1, &v2, &center)));
        };

      for x in 0..lateral_samples {
      for y in 0..lateral_samples {
      for z in 0..lateral_samples {
        let mut extract = |d_edge, d1, d2| {
          let w;
          {
            let iposition =
              if lg_size >= 0 {
                let mask = (1 << lg_size) - 1;
                assert!(
                  (iposition.x|iposition.y|iposition.z) & mask == 0,
                  "Block position should be a multiple of voxel sizes."
                );
                Point3::new(
                  iposition.x >> lg_size,
                  iposition.y >> lg_size,
                  iposition.z >> lg_size,
                )
              } else {
                let lg_size = -lg_size;
                Point3::new(
                  iposition.x << lg_size,
                  iposition.y << lg_size,
                  iposition.z << lg_size,
                )
              };
            w = iposition.add_v(&Vector3::new(x, y, z));
          }
          let voxel;
          let bounds = bounds_of(&w);
          match get_voxel(&bounds) {
            Voxel::Volume(_) => return,
            Voxel::Surface(v) => voxel = v,
          }

          {
            let neighbor_inside_surface;
            match get_voxel(&bounds_of(&w.add_v(&d_edge))) {
              Voxel::Volume(is_inside) => {
                neighbor_inside_surface = is_inside;
              },
              Voxel::Surface(neighbor) => {
                neighbor_inside_surface = neighbor.corner_inside_surface;
              },
            }
            let edge_is_uncrossed = voxel.corner_inside_surface == neighbor_inside_surface;
            if edge_is_uncrossed {
              return
            }
          }

          // Make a quad out of the vertices from the 4 voxels adjacent to this edge.
          // We know they have vertices in them because if the surface crosses an edge,
          // it must cross that edge's neighbors.

          let (v1, n1) = get_vertex!(&w.add_v(&d1).add_v(&d2));
          let (v2, n2) = get_vertex!(&w.add_v(&d1));
          let v3 = voxel.inner_vertex.to_world_vertex(&bounds);
          let n3 = voxel.normal.to_world_normal();
          let (v4, n4) = get_vertex!(&w.add_v(&d2));

          // Put a vertex at the average of the vertices.
          let center =
            v1.add_v(&v2.to_vec()).add_v(&v3.to_vec()).add_v(&v4.to_vec()).div_s(4.0);
          let center_normal = n1.add_v(&n2).add_v(&n3).add_v(&n4).div_s(4.0);

          let mut add_poly = |v1, n1, v2, n2| add_poly(v1, n1, v2, n2, center, center_normal);

          if voxel.corner_inside_surface {
            // The polys are visible from positive infinity.
            add_poly(v1, n1, v4, n4);
            add_poly(v4, n4, v3, n3);
            add_poly(v3, n3, v2, n2);
            add_poly(v2, n2, v1, n1);
          } else {
            // The polys are visible from negative infinity.
            add_poly(v1, n1, v2, n2);
            add_poly(v2, n2, v3, n3);
            add_poly(v3, n3, v4, n4);
            add_poly(v4, n4, v1, n1);
          }
        };

        extract(
          Vector3::new(1, 0, 0),
          Vector3::new(0, -1, 0),
          Vector3::new(0, 0, -1),
        );

        extract(
          Vector3::new(0, 1, 0),
          Vector3::new(0, 0, -1),
          Vector3::new(-1, 0, 0),
        );

        extract(
          Vector3::new(0, 0, 1),
          Vector3::new(-1, 0, 0),
          Vector3::new(0, -1, 0),
        );
      }}}
    }

    block
  })
}
<commit_msg>Change terrain generation to be more index-oriented<commit_after>use cgmath::{Point, Point3, Vector, Vector3};
use cgmath::Aabb3;
use std::cmp::{min, max, partial_min, partial_max};
use std::collections::hash_map;
use std::collections::HashMap;
use std::sync::Mutex;
use stopwatch::TimerSet;

use common::block_position::BlockPosition;
use common::entity::EntityId;
use common::id_allocator::IdAllocator;
use common::lod::LODIndex;
use common::terrain_block;
use common::terrain_block::{TerrainBlock, tri};

use heightmap::HeightMap;
use voxel;
use voxel::{Fracu8, Fraci8, Voxel, SurfaceVoxel, Vertex, Normal};
use voxel_tree;
use voxel_tree::VoxelTree;

pub fn generate_voxel(
  timers: &TimerSet,
  heightmap: &HeightMap,
  voxel: &voxel::Bounds,
) -> Voxel
{
  timers.time("generate_voxel", || {
    let field_contains = |x, y, z| {
      heightmap.density_at(x, y, z) >= 0.0
    };

    let get_normal = |x, y, z| {
      heightmap.normal_at(0.01, x, y, z)
    };

    let size = voxel.size();
    let (x1, y1, z1) = (voxel.x as f32 * size, voxel.y as f32 * size, voxel.z as f32 * size);
    let delta = size;
    let (x2, y2, z2) = (x1 + delta, y1 + delta, z1 + delta);
    // corners[x][y][z]
    let corners = [
      [
        [ field_contains(x1, y1, z1), field_contains(x1, y1, z2) ],
        [ field_contains(x1, y2, z1), field_contains(x1, y2, z2) ],
      ],
      [
        [ field_contains(x2, y1, z1), field_contains(x2, y1, z2) ],
        [ field_contains(x2, y2, z1), field_contains(x2, y2, z2) ],
      ],
    ];

    let corner;
    let mut any_inside = false;
    let mut all_inside = true;

    {
      let mut get_corner = |x1:usize, y1:usize, z1:usize| {
        let corner = corners[x1][y1][z1];
        any_inside = any_inside || corner;
        all_inside = all_inside && corner;
        corner
      };

      corner = get_corner(0,0,0);
      let _ = get_corner(0,0,1);
      let _ = get_corner(0,1,0);
      let _ = get_corner(0,1,1);
      let _ = get_corner(1,0,0);
      let _ = get_corner(1,0,1);
      let _ = get_corner(1,1,0);
      let _ = get_corner(1,1,1);
    }

    let all_corners_same = any_inside == all_inside;
    if all_corners_same {
      return Voxel::Volume(all_inside)
    }

    let mut vertex: Vector3<u32> = Vector3::new(0, 0, 0);
    let mut n = 0;
    for (&x, corners) in [0, 0xFF].iter().zip(corners.iter()) {
    for (&y, corners) in [0, 0xFF].iter().zip(corners.iter()) {
    for (&z, &corner) in [0, 0xFF].iter().zip(corners.iter()) {
      if corner {
        vertex.add_self_v(&Vector3::new(x, y, z));
        n += 1;
      }
    }}}

    {
      // Sample in extra areas to help weight the vertex to the appropriate place.
      let mut sample_extra = |lg_s: u8| {
        let fs = 1.0 / ((1 << lg_s) as f32);
        let mfs = 1.0 - fs;
        let s = 0x100 >> lg_s;
        let ms = 0x100 - s;
        for &(wx, x) in
          [((voxel.x as f32 + fs) * size, s), ((voxel.x as f32 + mfs) * size, ms)].iter() {
        for &(wy, y) in
          [((voxel.y as f32 + fs) * size, s), ((voxel.y as f32 + mfs) * size, ms)].iter() {
        for &(wz, z) in
          [((voxel.z as f32 + fs) * size, s), ((voxel.z as f32 + mfs) * size, ms)].iter() {
          if field_contains(wx, wy, wz) {
            vertex.add_self_v(&Vector3::new(x, y, z).mul_s(lg_s as u32));
            n += lg_s as u32;
          }
        }}}
      };

      sample_extra(2);
    }

    let vertex = vertex.div_s(n);
    let vertex =
      Vertex {
        x: Fracu8::of(vertex.x as u8),
        y: Fracu8::of(vertex.y as u8),
        z: Fracu8::of(vertex.z as u8),
      };

    let normal;
    {
      // Okay, this is silly to have right after we construct the vertex.
      let vertex = vertex.to_world_vertex(voxel);
      normal = get_normal(vertex.x, vertex.y, vertex.z).mul_s(127.0);
    }

    // Okay, so we scale the normal by 127, and use 127 to represent 1.0.
    // Then we store it in a `Fraci8`, which scales by 128 and represents a
    // fraction in [0,1). That seems wrong, but this is normal data, so scaling
    // doesn't matter. Sketch factor is over 9000, but it's not wrong.

    let normal = Vector3::new(normal.x as i32, normal.y as i32, normal.z as i32);
    let normal =
      Vector3::new(
        max(-127, min(127, normal.x)) as i8,
        max(-127, min(127, normal.y)) as i8,
        max(-127, min(127, normal.z)) as i8,
      );

    let normal =
      Normal {
        x: Fraci8::of(normal.x),
        y: Fraci8::of(normal.y),
        z: Fraci8::of(normal.z),
      };

    Voxel::Surface(SurfaceVoxel {
      inner_vertex: vertex,
      normal: normal,
      corner_inside_surface: corner,
    })
  })
}

fn make_bounds(
  v1: &Point3<f32>,
  v2: &Point3<f32>,
  v3: &Point3<f32>,
) -> Aabb3<f32> {
  let minx = partial_min(v1.x, v2.x);
  let minx = minx.and_then(|m| partial_min(m, v3.x));
  let minx = minx.unwrap();

  let maxx = partial_max(v1.x, v2.x);
  let maxx = maxx.and_then(|m| partial_max(m, v3.x));
  let maxx = maxx.unwrap();

  let miny = partial_min(v1.y, v2.y);
  let miny = miny.and_then(|m| partial_min(m, v3.y));
  let miny = miny.unwrap();

  let maxy = partial_max(v1.y, v2.y);
  let maxy = maxy.and_then(|m| partial_max(m, v3.y));
  let maxy = maxy.unwrap();

  let minz = partial_min(v1.z, v2.z);
  let minz = minz.and_then(|m| partial_min(m, v3.z));
  let minz = minz.unwrap();

  let maxz = partial_max(v1.z, v2.z);
  let maxz = maxz.and_then(|m| partial_max(m, v3.z));
  let maxz = maxz.unwrap();

  Aabb3::new(
    // TODO: Remove this - 1.0. It's a temporary hack until voxel collisions work,
    // to avoid zero-height Aabb3s.
    Point3::new(minx, miny - 1.0, minz),
    Point3::new(maxx, maxy, maxz),
  )
}

/// Generate a `TerrainBlock` based on a given position in a `VoxelTree`.
/// Any necessary voxels will be generated.
pub fn generate_block(
  timers: &TimerSet,
  id_allocator: &Mutex<IdAllocator<EntityId>>,
  heightmap: &HeightMap,
  voxels: &mut VoxelTree,
  position: &BlockPosition,
  lod_index: LODIndex,
) -> TerrainBlock {
  timers.time("update.generate_block", || {
    let mut block = TerrainBlock::empty();

    let lateral_samples = terrain_block::EDGE_SAMPLES[lod_index.0 as usize] as i32;
    let lg_size = terrain_block::LG_SAMPLE_SIZE[lod_index.0 as usize] as i16;

    let bounds_at = |v: &Point3<i32>| {
      voxel::Bounds::new(v.x, v.y, v.z, lg_size)
    };

    let mut get_voxel = |bounds: &voxel::Bounds| {
      let branch = voxels.get_mut_or_create(bounds);
      let r;
      match branch {
        &mut voxel_tree::TreeBody::Leaf(v) => r = v,
        &mut voxel_tree::TreeBody::Empty => {
          r = generate_voxel(timers, heightmap, bounds);
          *branch = voxel_tree::TreeBody::Leaf(r);
        },
        &mut voxel_tree::TreeBody::Branch(_) => {
          // Overwrite existing for now.
          // TODO: Don't do ^that.
          r = generate_voxel(timers, heightmap, bounds);
          *branch = voxel_tree::TreeBody::Leaf(r);
        },
      };
      r
    };

    let lg_ratio = terrain_block::LG_WIDTH - lg_size;
    let block_position = position.as_pnt();
    let voxel_position =
      Point3::new(
        block_position.x << lg_ratio,
        block_position.y << lg_ratio,
        block_position.z << lg_ratio,
      );

    let mut coords = Vec::new();
    let mut normals = Vec::new();
    let mut indices = HashMap::new();
    let mut polys = Vec::new();

    for dx in 0..lateral_samples {
    for dy in 0..lateral_samples {
    for dz in 0..lateral_samples {
      let voxel_position = voxel_position.add_v(&Vector3::new(dx, dy, dz));
      let voxel;
      let bounds = bounds_at(&voxel_position);
      match get_voxel(&bounds) {
        Voxel::Surface(v) => voxel = v,
        _ => continue,
      }
      let index = coords.len();
      let vertex = voxel.inner_vertex.to_world_vertex(&bounds);
      let normal = voxel.normal.to_world_normal();
      coords.push(vertex);
      normals.push(normal);
      indices.insert(voxel_position, index);

      let mut edge = |
        d_neighbor, // Vector to the neighbor to make an edge toward.
        d1, d2,     // Vector to the voxels adjacent to the edge.
      | {
        let neighbor_inside_surface;
        match get_voxel(&bounds_at(&voxel_position.add_v(&d_neighbor))) {
          Voxel::Surface(v) => neighbor_inside_surface = v.corner_inside_surface,
          Voxel::Volume(inside) => neighbor_inside_surface = inside,
        }
        if voxel.corner_inside_surface == neighbor_inside_surface {
          // This edge doesn't cross the surface, and doesn't generate polys.

          return
        }

        let v1; let v2; let v3; let v4;
        let n1; let n2; let n3; let n4;
        let i1; let i2; let i3; let i4;

        {
          let mut voxel_index = |position: &Point3<i32>| {
            match indices.entry(*position) {
              hash_map::Entry::Occupied(entry) => {
                let i = *entry.get();
                (coords[i], normals[i], i)
              },
              hash_map::Entry::Vacant(entry) => {
                let bounds = bounds_at(position);
                match get_voxel(&bounds) {
                  Voxel::Surface(voxel) => {
                    let i = coords.len();
                    let vertex = voxel.inner_vertex.to_world_vertex(&bounds);
                    let normal = voxel.normal.to_world_normal();
                    coords.push(vertex);
                    normals.push(normal);
                    entry.insert(i);
                    (vertex, normal, i)
                  },
                  _ => panic!("Unitialized neighbor"),
                }
              },
            }
          };

          let (tv1, tn1, ti1) = voxel_index(&voxel_position.add_v(&d1).add_v(&d2));
          let (tv2, tn2, ti2) = voxel_index(&voxel_position.add_v(&d1));
          let (tv3, tn3, ti3) = (vertex, normal, index);
          let (tv4, tn4, ti4) = voxel_index(&voxel_position.add_v(&d2));

          v1 = tv1; v2 = tv2; v3 = tv3; v4 = tv4;
          n1 = tn1; n2 = tn2; n3 = tn3; n4 = tn4;
          i1 = ti1; i2 = ti2; i3 = ti3; i4 = ti4;
        }

        // Put a vertex at the average of the vertices.
        let v_center =
          v1.add_v(&v2.to_vec()).add_v(&v3.to_vec()).add_v(&v4.to_vec()).div_s(4.0);
        let n_center =
          n1.add_v(&n2).add_v(&n3).add_v(&n4).div_s(4.0);

        let i_center = coords.len();
        coords.push(v_center);
        normals.push(n_center);

        if voxel.corner_inside_surface {
          // The polys are visible from positive infinity.
          polys.push([i2, i1, i_center]);
          polys.push([i3, i2, i_center]);
          polys.push([i4, i3, i_center]);
          polys.push([i1, i4, i_center]);
        } else {
          // The polys are visible from negative infinity.
          polys.push([i1, i2, i_center]);
          polys.push([i2, i3, i_center]);
          polys.push([i3, i4, i_center]);
          polys.push([i4, i1, i_center]);
        }
      };

      edge(
        Vector3::new(1, 0, 0),
        Vector3::new(0, -1, 0),
        Vector3::new(0, 0, -1),
      );

      edge(
        Vector3::new(0, 1, 0),
        Vector3::new(0, 0, -1),
        Vector3::new(-1, 0, 0),
      );

      edge(
        Vector3::new(0, 0, 1),
        Vector3::new(-1, 0, 0),
        Vector3::new(0, -1, 0),
      );
    }}}

    for poly in polys.iter() {
      block.vertex_coordinates.push(tri(coords[poly[0]], coords[poly[1]], coords[poly[2]]));
      block.normals.push(tri(normals[poly[0]], normals[poly[1]], normals[poly[2]]));

      let id = id_allocator.lock().unwrap().allocate();
      block.ids.push(id);
      block.bounds.push((id, make_bounds(&coords[poly[0]], &coords[poly[1]], &coords[poly[2]])));
    }

    block
  })
}
<|endoftext|>


<commit_before>#![feature(test, plugin, decl_macro)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate rocket_contrib;
#[macro_use]
extern crate rust_embed;

use rocket::http::{ContentType, Status};
use rocket::response;
use std::ffi::OsStr;
use std::io::Cursor;
use std::path::PathBuf;

#[derive(RustEmbed)]
#[folder = "examples/public/"]
struct Asset;

#[get("/")]
fn index<'r>() -> response::Result<'r> {
  Asset::get("index.html").map_or_else(
    || Err(Status::NotFound),
    |d| response::Response::build().header(ContentType::HTML).sized_body(Cursor::new(d)).ok(),
  )
}

#[get("/dist/<file..>")]
fn dist<'r>(file: PathBuf) -> response::Result<'r> {
  let filename = file.display().to_string();
  let ext = file.as_path().extension().and_then(OsStr::to_str).expect("Could not get file extension");
  let content_type = ContentType::from_extension(ext).expect("Could not get file content type");
  Asset::get(&filename.clone()).map_or_else(
    || Err(Status::NotFound),
    |d| response::Response::build().header(content_type).sized_body(Cursor::new(d)).ok(),
  )
}

fn main() {
  rocket::ignite().mount("/", routes![index, dist]).launch();
}
<commit_msg>avoid panics in rocket example<commit_after>#![feature(test, plugin, decl_macro)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate rocket_contrib;
#[macro_use]
extern crate rust_embed;

use rocket::http::{ContentType, Status};
use rocket::response;
use std::ffi::OsStr;
use std::io::Cursor;
use std::path::PathBuf;

#[derive(RustEmbed)]
#[folder = "examples/public/"]
struct Asset;

#[get("/")]
fn index<'r>() -> response::Result<'r> {
  Asset::get("index.html").map_or_else(
    || Err(Status::NotFound),
    |d| response::Response::build().header(ContentType::HTML).sized_body(Cursor::new(d)).ok(),
  )
}

#[get("/dist/<file..>")]
fn dist<'r>(file: PathBuf) -> response::Result<'r> {
  let filename = file.display().to_string();
  Asset::get(&filename).map_or_else(
    || Err(Status::NotFound),
    |d| {
      let ext = file
        .as_path()
        .extension()
        .and_then(OsStr::to_str)
        .ok_or(Status::new(400, "Could not get file extension"))?;
      let content_type = ContentType::from_extension(ext).ok_or(Status::new(400, "Could not get file content type"))?;
      response::Response::build().header(content_type).sized_body(Cursor::new(d)).ok()
    },
  )
}

fn main() {
  rocket::ignite().mount("/", routes![index, dist]).launch();
}
<|endoftext|>


<commit_before>#![allow(unstable)]

extern crate iron;
extern crate "handlebars-iron" as hbs;
extern crate "rustc-serialize" as serialize;

use iron::prelude::*;
use iron::ChainBuilder;
use hbs::{Template, HandlebarsEngine};
use serialize::json::{ToJson, Json};
use std::collections::BTreeMap;

/// this function is for making example data
fn make_data() -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let mut teams = Vec::new();

    for v in vec![("Jiangsu", 43u16), ("Beijing", 27u16), ("Guangzhou", 22u16), ("Shandong", 12u16)].iter() {
        let (name, score) = *v;
        let mut t = BTreeMap::new();
        t.insert("name".to_string(), name.to_json());
        t.insert("score".to_string(), score.to_json());
        teams.push(t)
    }

    data.insert("teams".to_string(), teams.to_json());
    data
}

/// the handler
fn hello_world(_: &mut Request) -> IronResult<Response> {
    let resp = Response::new();

    let data = make_data();
    Ok(resp.set(Template::new("index", data)))
}

fn main() {
    let mut chain = ChainBuilder::new(hello_world);
    chain.link_after(HandlebarsEngine::new("./examples/templates/", ".hbs"));
    Iron::new(chain).listen("localhost:3000").unwrap();
}
<commit_msg>(fix) set status code in user handler as middleware changed<commit_after>#![allow(unstable)]

extern crate iron;
extern crate "handlebars-iron" as hbs;
extern crate "rustc-serialize" as serialize;

use iron::prelude::*;
use iron::{ChainBuilder, status};
use hbs::{Template, HandlebarsEngine};
use serialize::json::{ToJson, Json};
use std::collections::BTreeMap;

/// this function is for making example data
fn make_data() -> BTreeMap<String, Json> {
    let mut data = BTreeMap::new();

    data.insert("year".to_string(), "2015".to_json());

    let mut teams = Vec::new();

    for v in vec![("Jiangsu", 43u16), ("Beijing", 27u16), ("Guangzhou", 22u16), ("Shandong", 12u16)].iter() {
        let (name, score) = *v;
        let mut t = BTreeMap::new();
        t.insert("name".to_string(), name.to_json());
        t.insert("score".to_string(), score.to_json());
        teams.push(t)
    }

    data.insert("teams".to_string(), teams.to_json());
    data
}

/// the handler
fn hello_world(_: &mut Request) -> IronResult<Response> {
    let mut resp = Response::new();

    let data = make_data();
    resp.set_mut(Template::new("index", data)).set_mut(status::Ok);
    Ok(resp)
}

fn main() {
    let mut chain = ChainBuilder::new(hello_world);
    chain.link_after(HandlebarsEngine::new("./examples/templates/", ".hbs"));
    Iron::new(chain).listen("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate rbpf;
use rbpf::helpers;

// The main objectives of this example is to show:
//
// * the use of EbpfVmNoData function,
// * and the use of a helper.
//
// The two eBPF programs are independent and are not related to one another.
fn main() {
    let prog1 = vec![
        0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov32 r0, 0
        0xb4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov32 r1, 2
        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // add32 r0, 1
        0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // add32 r0, r1
        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit and return r0
    ];

    // We use helper `bpf_time_getns()`, which is similar to helper `bpf_ktime_getns()` from Linux
    // kernel. Hence rbpf::helpers module provides the index of this in-kernel helper as a
    // constant, so that we can remain compatible with programs for the kernel. Here we also cast
    // it to a u8 so as to use it directly in program instructions.
    let hkey = helpers::BPF_KTIME_GETNS_IDX as u8;
    let prog2 = vec![
        0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0x85, 0x00, 0x00, 0x00, hkey, 0x00, 0x00, 0x00, // call helper <hkey>
        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit and return r0
    ];

    // Create a VM: this one takes no data. Load prog1 in it.
    let mut vm = rbpf::EbpfVmNoData::new(&prog1);
    // Execute prog1.
    assert_eq!(vm.prog_exec(), 0x3);

    // As struct EbpfVmNoData does not takes any memory area, its return value is mostly
    // deterministic. So we know prog1 will always return 3. There is an exception: when it uses
    // helpers, the latter may have non-deterministic values, and all calls may not return the same
    // value.
    //
    // In the following example we use a helper to get the elapsed time since boot time: we
    // reimplement uptime in eBPF, in Rust. Because why not.

    vm.set_prog(&prog2);
    vm.register_helper(helpers::BPF_KTIME_GETNS_IDX, helpers::bpf_time_getns);

    vm.jit_compile();
    let t = unsafe { vm.prog_exec_jit() };

    let d =  t / 10u64.pow(9)  / 60   / 60  / 24;
    let h = (t / 10u64.pow(9)  / 60   / 60) % 24;
    let m = (t / 10u64.pow(9)  / 60 ) % 60;
    let s = (t / 10u64.pow(9)) % 60;
    let ns = t % 10u64.pow(9);

    println!("Uptime: {:#x} ns == {} days {:02}:{:02}:{:02}, {} ns", t, d, h, m, s, ns);
}
<commit_msg>examples/uptime.rs: fix copyright year<commit_after>// Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate rbpf;
use rbpf::helpers;

// The main objectives of this example is to show:
//
// * the use of EbpfVmNoData function,
// * and the use of a helper.
//
// The two eBPF programs are independent and are not related to one another.
fn main() {
    let prog1 = vec![
        0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov32 r0, 0
        0xb4, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov32 r1, 2
        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // add32 r0, 1
        0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // add32 r0, r1
        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit and return r0
    ];

    // We use helper `bpf_time_getns()`, which is similar to helper `bpf_ktime_getns()` from Linux
    // kernel. Hence rbpf::helpers module provides the index of this in-kernel helper as a
    // constant, so that we can remain compatible with programs for the kernel. Here we also cast
    // it to a u8 so as to use it directly in program instructions.
    let hkey = helpers::BPF_KTIME_GETNS_IDX as u8;
    let prog2 = vec![
        0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov64 r1, 0
        0x85, 0x00, 0x00, 0x00, hkey, 0x00, 0x00, 0x00, // call helper <hkey>
        0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit and return r0
    ];

    // Create a VM: this one takes no data. Load prog1 in it.
    let mut vm = rbpf::EbpfVmNoData::new(&prog1);
    // Execute prog1.
    assert_eq!(vm.prog_exec(), 0x3);

    // As struct EbpfVmNoData does not takes any memory area, its return value is mostly
    // deterministic. So we know prog1 will always return 3. There is an exception: when it uses
    // helpers, the latter may have non-deterministic values, and all calls may not return the same
    // value.
    //
    // In the following example we use a helper to get the elapsed time since boot time: we
    // reimplement uptime in eBPF, in Rust. Because why not.

    vm.set_prog(&prog2);
    vm.register_helper(helpers::BPF_KTIME_GETNS_IDX, helpers::bpf_time_getns);

    vm.jit_compile();
    let t = unsafe { vm.prog_exec_jit() };

    let d =  t / 10u64.pow(9)  / 60   / 60  / 24;
    let h = (t / 10u64.pow(9)  / 60   / 60) % 24;
    let m = (t / 10u64.pow(9)  / 60 ) % 60;
    let s = (t / 10u64.pow(9)) % 60;
    let ns = t % 10u64.pow(9);

    println!("Uptime: {:#x} ns == {} days {:02}:{:02}:{:02}, {} ns", t, d, h, m, s, ns);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

fn main() {
    let dir: PathBuf = ["../tree-sitter-ruby", "src"].iter().collect();
    let mut build = cc::Build::new();
    build
        .include(&dir)
        .file(&dir.join("parser.c"))
        .file(&dir.join("scanner.cc"));
    if !cfg!(windows) {
        build.cpp(true).compiler("clang");
    }
    build.compile("tree-sitter-ruby");
}
<commit_msg>Build parser.c and scanner.cc separately<commit_after>use std::path::PathBuf;

fn main() {
    let src_dir: PathBuf = ["..", "tree-sitter-ruby", "src"].iter().collect();

    let mut c_config = cc::Build::new();
    c_config.include(&src_dir);
    c_config
        .flag_if_supported("-Wno-unused-parameter")
        .flag_if_supported("-Wno-unused-but-set-variable")
        .flag_if_supported("-Wno-trigraphs");
    let parser_path = src_dir.join("parser.c");
    c_config.file(&parser_path);
    println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap());
    c_config.compile("parser");

    let mut cpp_config = cc::Build::new();
    cpp_config.cpp(true);
    cpp_config.include(&src_dir);
    cpp_config
        .flag_if_supported("-Wno-unused-parameter")
        .flag_if_supported("-Wno-unused-but-set-variable");
    let scanner_path = src_dir.join("scanner.cc");
    cpp_config.file(&scanner_path);
    println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap());
    cpp_config.compile("scanner");
}
<|endoftext|>


<commit_before>//! Functions used in protobuf tests

pub mod build;
pub mod hex;

mod serialize_deserialize_generated;
pub use serialize_deserialize_generated::*;

mod serialize_deserialize_dynamic;
pub use serialize_deserialize_dynamic::*;

mod serialize_deserialize_both;
pub use serialize_deserialize_both::*;

mod text_format_tests;
pub use text_format_tests::*;

mod json_tests;
pub use json_tests::*;

mod reflect_tests;
pub use reflect_tests::*;

mod cargo;
pub use cargo::*;

mod interop;
pub use interop::*;

mod dynamic;
pub use dynamic::*;
<commit_msg>Readme<commit_after>//! Random code uses in protobuf test crates.

pub mod build;
pub mod hex;

mod serialize_deserialize_generated;
pub use serialize_deserialize_generated::*;

mod serialize_deserialize_dynamic;
pub use serialize_deserialize_dynamic::*;

mod serialize_deserialize_both;
pub use serialize_deserialize_both::*;

mod text_format_tests;
pub use text_format_tests::*;

mod json_tests;
pub use json_tests::*;

mod reflect_tests;
pub use reflect_tests::*;

mod cargo;
pub use cargo::*;

mod interop;
pub use interop::*;

mod dynamic;
pub use dynamic::*;
<|endoftext|>


<commit_before>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// 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.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;

use freetype::Library;
use freetype::Face;
use freetype;

mod list_fonts;

use self::list_fonts::{Family, get_font_families};
use super::{FontDesc, RasterizedGlyph, Metrics};

/// Rasterizes glyphs for a single font face.
pub struct Rasterizer {
    faces: HashMap<FontDesc, Face<'static>>,
    library: Library,
    system_fonts: HashMap<String, Family>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

// #[inline]
// fn freetype_26_6_to_float(val: i64) -> f64 {
//     val as f64 / (1i64 << 6) as f64
// }

impl Rasterizer {
    pub fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32) -> Rasterizer {
        let library = Library::init().unwrap();

        Rasterizer {
            system_fonts: get_font_families(),
            faces: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        }
    }

    pub fn metrics(&mut self, desc: &FontDesc, size: f32) -> Metrics {
        let face = self.get_face(&desc).unwrap();

        let scale_size = self.dpr as f64 * size as f64;

        let em_size = face.em_size() as f64;
        let w = face.max_advance_width() as f64;
        let h = (face.ascender() - face.descender() + face.height()) as f64;

        let w_scale = w * scale_size / em_size;
        let h_scale = h * scale_size / em_size;

        Metrics {
            average_advance: w_scale,
            line_height: h_scale,
        }
    }

    fn get_face(&mut self, desc: &FontDesc) -> Option<Face<'static>> {
        if let Some(face) = self.faces.get(desc) {
            return Some(face.clone());
        }

        if let Some(font) = self.system_fonts.get(&desc.name[..]) {
            if let Some(variant) = font.variants().get(&desc.style[..]) {
                let face = self.library.new_face(variant.path(), variant.index())
                                       .expect("TODO handle new_face error");

                self.faces.insert(desc.to_owned(), face);
                return Some(self.faces.get(desc).unwrap().clone());
            }
        }

        None
    }

    pub fn get_glyph(&mut self, desc: &FontDesc, size: f32, c: char) -> RasterizedGlyph {
        let face = self.get_face(desc).expect("TODO handle get_face error");
        face.set_char_size(to_freetype_26_6(size * self.dpr), 0, self.dpi_x, self.dpi_y).unwrap();
        face.load_char(c as usize, freetype::face::TARGET_LIGHT).unwrap();
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd).unwrap();

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(ft_lib, freetype::ffi::FT_LCD_FILTER_DEFAULT);
        }

        let bitmap = glyph.bitmap();
        let buf = bitmap.buffer();
        let pitch = bitmap.pitch() as usize;

        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        for i in 0..bitmap.rows() {
            let start = (i as usize) * pitch;
            let stop = start + bitmap.width() as usize;
            packed.extend_from_slice(&buf[start..stop]);
        }

        RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: glyph.bitmap().width() / 3,
            height: glyph.bitmap().rows(),
            buf: packed,
        }
    }
}

unsafe impl Send for Rasterizer {}

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

    fn font_desc() -> FontDesc {
        FontDesc::new("Ubuntu Mono", "Regular")
    }
}
<commit_msg>Support bold/italic font rendering on Linux<commit_after>// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// 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.
//
//! Rasterization powered by FreeType and FontConfig
use std::collections::HashMap;

use freetype::Library;
use freetype::Face;
use freetype;

mod list_fonts;

use self::list_fonts::{Family, get_font_families};
use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey};

/// Rasterizes glyphs for a single font face.
pub struct Rasterizer {
    faces: HashMap<FontKey, Face<'static>>,
    library: Library,
    system_fonts: HashMap<String, Family>,
    dpi_x: u32,
    dpi_y: u32,
    dpr: f32,
}

#[inline]
fn to_freetype_26_6(f: f32) -> isize {
    ((1i32 << 6) as f32 * f) as isize
}

// #[inline]
// fn freetype_26_6_to_float(val: i64) -> f64 {
//     val as f64 / (1i64 << 6) as f64
// }

impl Rasterizer {
    pub fn new(dpi_x: f32, dpi_y: f32, device_pixel_ratio: f32) -> Rasterizer {
        let library = Library::init().unwrap();

        Rasterizer {
            system_fonts: get_font_families(),
            faces: HashMap::new(),
            library: library,
            dpi_x: dpi_x as u32,
            dpi_y: dpi_y as u32,
            dpr: device_pixel_ratio,
        }
    }

    pub fn metrics(&self, key: FontKey, size: Size) -> Metrics {
        let face = self.faces.get(&key).unwrap();

        let scale_size = self.dpr as f64 * size.as_f32_pts() as f64;

        let em_size = face.em_size() as f64;
        let w = face.max_advance_width() as f64;
        let h = (face.ascender() - face.descender() + face.height()) as f64;

        let w_scale = w * scale_size / em_size;
        let h_scale = h * scale_size / em_size;

        Metrics {
            average_advance: w_scale,
            line_height: h_scale,
        }
    }

    pub fn load_font(&mut self, desc: &FontDesc, _size: Size) -> Option<FontKey> {
        self.get_face(desc)
            .map(|face| {
                let key = FontKey::next();
                self.faces.insert(key, face);
                key
            })
    }

    fn get_face(&mut self, desc: &FontDesc) -> Option<Face<'static>> {
        self.system_fonts
            .get(&desc.name[..])
            .and_then(|font| font.variants().get(&desc.style[..]))
            .map(|variant| {
                self.library.new_face(variant.path(), variant.index())
                            .expect("TODO handle new_face error")
            })
    }

    pub fn get_glyph(&mut self, glyph_key: &GlyphKey) -> RasterizedGlyph {
        let face = self.faces
            .get(&glyph_key.font_key)
            .expect("TODO handle get_face error");

        let size = glyph_key.size.as_f32_pts() * self.dpr;
        let c = glyph_key.c;

        face.set_char_size(to_freetype_26_6(size), 0, self.dpi_x, self.dpi_y).unwrap();
        face.load_char(c as usize, freetype::face::TARGET_LIGHT).unwrap();
        let glyph = face.glyph();
        glyph.render_glyph(freetype::render_mode::RenderMode::Lcd).unwrap();

        unsafe {
            let ft_lib = self.library.raw();
            freetype::ffi::FT_Library_SetLcdFilter(ft_lib, freetype::ffi::FT_LCD_FILTER_DEFAULT);
        }

        let bitmap = glyph.bitmap();
        let buf = bitmap.buffer();
        let pitch = bitmap.pitch() as usize;

        let mut packed = Vec::with_capacity((bitmap.rows() * bitmap.width()) as usize);
        for i in 0..bitmap.rows() {
            let start = (i as usize) * pitch;
            let stop = start + bitmap.width() as usize;
            packed.extend_from_slice(&buf[start..stop]);
        }

        RasterizedGlyph {
            c: c,
            top: glyph.bitmap_top(),
            left: glyph.bitmap_left(),
            width: glyph.bitmap().width() / 3,
            height: glyph.bitmap().rows(),
            buf: packed,
        }
    }
}

unsafe impl Send for Rasterizer {}

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

    fn font_desc() -> FontDesc {
        FontDesc::new("Ubuntu Mono", "Regular")
    }
}
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![doc = include_str!("../README.md")]
#![warn(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![deny(missing_docs)]

mod render;

pub use roff;

use render::subcommand_heading;
use roff::{roman, Roff};
use std::io::Write;

/// A manual page as constructed from a clap::App.
pub struct Man<'a> {
    app: clap::App<'a>,
    title: String,
    section: String,
    date: String,
    source: String,
    manual: String,
}

impl<'a> Man<'a> {
    /// Create a new manual page.
    pub fn new(mut app: clap::App<'a>) -> Self {
        app._build_all();
        let title = app.get_name().to_owned();
        let section = "1".to_owned();
        let date = "".to_owned();
        let source = format!(
            "{} {}",
            app.get_name(),
            app.get_version().unwrap_or_default()
        );
        let manual = "".to_owned();
        Self {
            app,
            title,
            section,
            date,
            source,
            manual,
        }
    }

    /// Override the default title
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Override the default section
    pub fn section(mut self, section: impl Into<String>) -> Self {
        self.section = section.into();
        self
    }

    /// Override the default date
    pub fn date(mut self, date: impl Into<String>) -> Self {
        self.date = date.into();
        self
    }

    /// Override the default source
    pub fn source(mut self, source: impl Into<String>) -> Self {
        self.source = source.into();
        self
    }

    /// Override the default manual
    pub fn manual(mut self, manual: impl Into<String>) -> Self {
        self.manual = manual.into();
        self
    }

    /// Render a manual page into writer.
    pub fn render(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        roff.control("TH", self.title_args());
        self._render_name_section(&mut roff);
        self._render_synopsis_section(&mut roff);
        self._render_description_section(&mut roff);

        if app_has_arguments(&self.app) {
            self._render_options_section(&mut roff);
        }

        if app_has_subcommands(&self.app) {
            self._render_subcommands_section(&mut roff);
        }

        if self.app.get_after_long_help().is_some() || self.app.get_after_help().is_some() {
            self._render_extra_section(&mut roff);
        }

        if app_has_version(&self.app) {
            self._render_version_section(&mut roff);
        }

        if self.app.get_author().is_some() {
            self._render_authors_section(&mut roff);
        }

        roff.to_writer(w)
    }

    // Turn metadata into arguments for a .TH macro.
    fn title_args(&self) -> Vec<&str> {
        vec![
            &self.title,
            &self.section,
            &self.date,
            &self.source,
            &self.manual,
        ]
    }

    /// Render the NAME section into the writer.
    pub fn render_name_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_name_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_name_section(&self, roff: &mut Roff) {
        roff.control("SH", ["NAME"]);
        render::about(roff, &self.app);
    }

    /// Render the SYNOPSIS section into the writer.
    pub fn render_synopsis_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_synopsis_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_synopsis_section(&self, roff: &mut Roff) {
        roff.control("SH", ["SYNOPSIS"]);
        render::synopsis(roff, &self.app);
    }

    /// Render the DESCRIPTION section into the writer.
    pub fn render_description_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_description_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_description_section(&self, roff: &mut Roff) {
        roff.control("SH", ["DESCRIPTION"]);
        render::description(roff, &self.app);
    }

    /// Render the OPTIONS section into the writer.
    pub fn render_options_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_options_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_options_section(&self, roff: &mut Roff) {
        roff.control("SH", ["OPTIONS"]);
        render::options(roff, &self.app);
    }

    /// Render the SUBCOMMANDS section into the writer.
    pub fn render_subcommands_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_subcommands_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_subcommands_section(&self, roff: &mut Roff) {
        let heading = subcommand_heading(&self.app);
        roff.control("SH", [heading.as_str()]);
        render::subcommands(roff, &self.app, &self.section);
    }

    /// Render the EXTRA section into the writer.
    pub fn render_extra_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_extra_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_extra_section(&self, roff: &mut Roff) {
        roff.control("SH", ["EXTRA"]);
        render::after_help(roff, &self.app);
    }

    /// Render the VERSION section into the writer.
    pub fn render_version_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_version_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_version_section(&self, roff: &mut Roff) {
        let version = roman(&render::version(&self.app));
        roff.control("SH", ["VERSION"]);
        roff.text([version]);
    }

    /// Render the AUTHORS section into the writer.
    pub fn render_authors_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_authors_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_authors_section(&self, roff: &mut Roff) {
        let author = roman(self.app.get_author().unwrap_or_default());
        roff.control("SH", ["AUTHORS"]);
        roff.text([author]);
    }
}

// Does the application have a version?
fn app_has_version(app: &clap::App) -> bool {
    app.get_version()
        .or_else(|| app.get_long_version())
        .is_some()
}

// Does the application have any command line arguments?
fn app_has_arguments(app: &clap::App) -> bool {
    app.get_arguments()
        .any(|i| !i.is_set(clap::ArgSettings::Hidden))
}

// Does the application have any subcommands?
fn app_has_subcommands(app: &clap::App) -> bool {
    app.get_subcommands()
        .any(|i| !i.is_set(clap::AppSettings::Hidden))
}
<commit_msg>fix(man): Expose title generation<commit_after>#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![doc = include_str!("../README.md")]
#![warn(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![deny(missing_docs)]

mod render;

pub use roff;

use render::subcommand_heading;
use roff::{roman, Roff};
use std::io::Write;

/// A manual page as constructed from a clap::App.
pub struct Man<'a> {
    app: clap::App<'a>,
    title: String,
    section: String,
    date: String,
    source: String,
    manual: String,
}

impl<'a> Man<'a> {
    /// Create a new manual page.
    pub fn new(mut app: clap::App<'a>) -> Self {
        app._build_all();
        let title = app.get_name().to_owned();
        let section = "1".to_owned();
        let date = "".to_owned();
        let source = format!(
            "{} {}",
            app.get_name(),
            app.get_version().unwrap_or_default()
        );
        let manual = "".to_owned();
        Self {
            app,
            title,
            section,
            date,
            source,
            manual,
        }
    }

    /// Override the default title
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Override the default section
    pub fn section(mut self, section: impl Into<String>) -> Self {
        self.section = section.into();
        self
    }

    /// Override the default date
    pub fn date(mut self, date: impl Into<String>) -> Self {
        self.date = date.into();
        self
    }

    /// Override the default source
    pub fn source(mut self, source: impl Into<String>) -> Self {
        self.source = source.into();
        self
    }

    /// Override the default manual
    pub fn manual(mut self, manual: impl Into<String>) -> Self {
        self.manual = manual.into();
        self
    }

    /// Render a manual page into writer.
    pub fn render(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_title(&mut roff);
        self._render_name_section(&mut roff);
        self._render_synopsis_section(&mut roff);
        self._render_description_section(&mut roff);

        if app_has_arguments(&self.app) {
            self._render_options_section(&mut roff);
        }

        if app_has_subcommands(&self.app) {
            self._render_subcommands_section(&mut roff);
        }

        if self.app.get_after_long_help().is_some() || self.app.get_after_help().is_some() {
            self._render_extra_section(&mut roff);
        }

        if app_has_version(&self.app) {
            self._render_version_section(&mut roff);
        }

        if self.app.get_author().is_some() {
            self._render_authors_section(&mut roff);
        }

        roff.to_writer(w)
    }

    /// Render the title into the writer.
    pub fn render_title(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_title(&mut roff);
        roff.to_writer(w)
    }

    fn _render_title(&self, roff: &mut Roff) {
        roff.control("TH", self.title_args());
    }

    // Turn metadata into arguments for a .TH macro.
    fn title_args(&self) -> Vec<&str> {
        vec![
            &self.title,
            &self.section,
            &self.date,
            &self.source,
            &self.manual,
        ]
    }

    /// Render the NAME section into the writer.
    pub fn render_name_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_name_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_name_section(&self, roff: &mut Roff) {
        roff.control("SH", ["NAME"]);
        render::about(roff, &self.app);
    }

    /// Render the SYNOPSIS section into the writer.
    pub fn render_synopsis_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_synopsis_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_synopsis_section(&self, roff: &mut Roff) {
        roff.control("SH", ["SYNOPSIS"]);
        render::synopsis(roff, &self.app);
    }

    /// Render the DESCRIPTION section into the writer.
    pub fn render_description_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_description_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_description_section(&self, roff: &mut Roff) {
        roff.control("SH", ["DESCRIPTION"]);
        render::description(roff, &self.app);
    }

    /// Render the OPTIONS section into the writer.
    pub fn render_options_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_options_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_options_section(&self, roff: &mut Roff) {
        roff.control("SH", ["OPTIONS"]);
        render::options(roff, &self.app);
    }

    /// Render the SUBCOMMANDS section into the writer.
    pub fn render_subcommands_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_subcommands_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_subcommands_section(&self, roff: &mut Roff) {
        let heading = subcommand_heading(&self.app);
        roff.control("SH", [heading.as_str()]);
        render::subcommands(roff, &self.app, &self.section);
    }

    /// Render the EXTRA section into the writer.
    pub fn render_extra_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_extra_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_extra_section(&self, roff: &mut Roff) {
        roff.control("SH", ["EXTRA"]);
        render::after_help(roff, &self.app);
    }

    /// Render the VERSION section into the writer.
    pub fn render_version_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_version_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_version_section(&self, roff: &mut Roff) {
        let version = roman(&render::version(&self.app));
        roff.control("SH", ["VERSION"]);
        roff.text([version]);
    }

    /// Render the AUTHORS section into the writer.
    pub fn render_authors_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_authors_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_authors_section(&self, roff: &mut Roff) {
        let author = roman(self.app.get_author().unwrap_or_default());
        roff.control("SH", ["AUTHORS"]);
        roff.text([author]);
    }
}

// Does the application have a version?
fn app_has_version(app: &clap::App) -> bool {
    app.get_version()
        .or_else(|| app.get_long_version())
        .is_some()
}

// Does the application have any command line arguments?
fn app_has_arguments(app: &clap::App) -> bool {
    app.get_arguments()
        .any(|i| !i.is_set(clap::ArgSettings::Hidden))
}

// Does the application have any subcommands?
fn app_has_subcommands(app: &clap::App) -> bool {
    app.get_subcommands()
        .any(|i| !i.is_set(clap::AppSettings::Hidden))
}
<|endoftext|>


<commit_before>use syscall::io::{Io, Pio};
use time;

use acpi;

pub fn init() {
    let mut rtc = Rtc::new();
    time::START.lock().0 = rtc.time();
}

fn cvt_bcd(value: usize) -> usize {
    (value & 0xF) + ((value / 16) * 10)
}

/// RTC
pub struct Rtc {
    addr: Pio<u8>,
    data: Pio<u8>,
}

impl Rtc {
    /// Create new empty RTC
    pub fn new() -> Self {
        return Rtc {
            addr: Pio::<u8>::new(0x70),
            data: Pio::<u8>::new(0x71),
        };
    }

    /// Read
    unsafe fn read(&mut self, reg: u8) -> u8 {
        self.addr.write(reg);
        return self.data.read();
    }

    /// Wait
    unsafe fn wait(&mut self) {
        while self.read(0xA) & 0x80 != 0x80 {}
        while self.read(0xA) & 0x80 == 0x80 {}
    }

    /// Get time
    pub fn time(&mut self) -> u64 {
        let mut second;
        let mut minute;
        let mut hour;
        let mut day;
        let mut month;
        let mut year;
        let mut century;
        let register_b;

        let century_register = if let Some(ref fadt) = acpi::ACPI_TABLE.lock().fadt {
            Some(fadt.century)
        } else {
            None
        };

        unsafe {
            self.wait();
            second = self.read(0) as usize;
            minute = self.read(2) as usize;
            hour = self.read(4) as usize;
            day = self.read(7) as usize;
            month = self.read(8) as usize;
            year = self.read(9) as usize;
            century = if let Some(century_reg) = century_register {
                self.read(century_reg) as usize
            } else {
                20 as usize
            };
            register_b = self.read(0xB);
        }

        if register_b & 4 != 4 {
            second = cvt_bcd(second);
            minute = cvt_bcd(minute);
            hour = cvt_bcd(hour & 0x7F) | (hour & 0x80);
            day = cvt_bcd(day);
            month = cvt_bcd(month);
            year = cvt_bcd(year);
            century = if century_register.is_some() {
                cvt_bcd(century)
            } else {
                century
            };
        }

        if register_b & 2 != 2 || hour & 0x80 == 0x80 {
            hour = ((hour & 0x7F) + 12) % 24;
        }

        year += century * 100;

        // Unix time from clock
        let mut secs: u64 = (year as u64 - 1970) * 31536000;

        let mut leap_days = (year as u64 - 1972) / 4 + 1;
        if year % 4 == 0 {
            if month <= 2 {
                leap_days -= 1;
            }
        }
        secs += leap_days * 86400;

        match month {
            2 => secs += 2678400,
            3 => secs += 5097600,
            4 => secs += 7776000,
            5 => secs += 10368000,
            6 => secs += 13046400,
            7 => secs += 15638400,
            8 => secs += 18316800,
            9 => secs += 20995200,
            10 => secs += 23587200,
            11 => secs += 26265600,
            12 => secs += 28857600,
            _ => (),
        }

        secs += (day as u64 - 1) * 86400;
        secs += hour as u64 * 3600;
        secs += minute as u64 * 60;
        secs += second as u64;

        secs
    }
}
<commit_msg>Disable century register for now<commit_after>use syscall::io::{Io, Pio};
use time;

use acpi;

pub fn init() {
    let mut rtc = Rtc::new();
    time::START.lock().0 = rtc.time();
}

fn cvt_bcd(value: usize) -> usize {
    (value & 0xF) + ((value / 16) * 10)
}

/// RTC
pub struct Rtc {
    addr: Pio<u8>,
    data: Pio<u8>,
}

impl Rtc {
    /// Create new empty RTC
    pub fn new() -> Self {
        return Rtc {
            addr: Pio::<u8>::new(0x70),
            data: Pio::<u8>::new(0x71),
        };
    }

    /// Read
    unsafe fn read(&mut self, reg: u8) -> u8 {
        self.addr.write(reg);
        return self.data.read();
    }

    /// Wait
    unsafe fn wait(&mut self) {
        while self.read(0xA) & 0x80 != 0x80 {}
        while self.read(0xA) & 0x80 == 0x80 {}
    }

    /// Get time
    pub fn time(&mut self) -> u64 {
        let mut second;
        let mut minute;
        let mut hour;
        let mut day;
        let mut month;
        let mut year;
        let mut century;
        let register_b;

        let century_register = if let Some(ref fadt) = acpi::ACPI_TABLE.lock().fadt {
            Some(fadt.century)
        } else {
            None
        };

        unsafe {
            self.wait();
            second = self.read(0) as usize;
            minute = self.read(2) as usize;
            hour = self.read(4) as usize;
            day = self.read(7) as usize;
            month = self.read(8) as usize;
            year = self.read(9) as usize;
            century = /* TODO: Fix invalid value from VirtualBox
            if let Some(century_reg) = century_register {
                self.read(century_reg) as usize
            } else */ {
                20 as usize
            };
            register_b = self.read(0xB);
        }

        if register_b & 4 != 4 {
            second = cvt_bcd(second);
            minute = cvt_bcd(minute);
            hour = cvt_bcd(hour & 0x7F) | (hour & 0x80);
            day = cvt_bcd(day);
            month = cvt_bcd(month);
            year = cvt_bcd(year);
            century = /* TODO: Fix invalid value from VirtualBox
            if century_register.is_some() {
                cvt_bcd(century)
            } else */ {
                century
            };
        }

        if register_b & 2 != 2 || hour & 0x80 == 0x80 {
            hour = ((hour & 0x7F) + 12) % 24;
        }

        year += century * 100;

        // Unix time from clock
        let mut secs: u64 = (year as u64 - 1970) * 31536000;

        let mut leap_days = (year as u64 - 1972) / 4 + 1;
        if year % 4 == 0 {
            if month <= 2 {
                leap_days -= 1;
            }
        }
        secs += leap_days * 86400;

        match month {
            2 => secs += 2678400,
            3 => secs += 5097600,
            4 => secs += 7776000,
            5 => secs += 10368000,
            6 => secs += 13046400,
            7 => secs += 15638400,
            8 => secs += 18316800,
            9 => secs += 20995200,
            10 => secs += 23587200,
            11 => secs += 26265600,
            12 => secs += 28857600,
            _ => (),
        }

        secs += (day as u64 - 1) * 86400;
        secs += hour as u64 * 3600;
        secs += minute as u64 * 60;
        secs += second as u64;

        secs
    }
}
<|endoftext|>


<commit_before>use flowgger::config::Config;
use flowgger::record::{Record, StructuredData, SDValue, SEVERITY_MAX};
use flowgger::utils;
use serde_json::de;
use serde_json::value::Value;
use super::Decoder;

#[derive(Clone)]
pub struct GelfDecoder;

impl GelfDecoder {
    pub fn new(_config: &Config) -> GelfDecoder {
        GelfDecoder
    }
}

impl Decoder for GelfDecoder {
    fn decode(&self, line: &str) -> Result<Record, &'static str> {
        let mut sd = StructuredData::new(None);
        let mut ts = None;
        let mut hostname = None;
        let mut msg = None;
        let mut full_msg = None;
        let mut severity = None;

        let obj: Value = try!(de::from_str(line)
            .or(Err("Invalid GELF input, unable to parse as a JSON object")));
        let obj = try!(obj.as_object().ok_or("Empty GELF input"));
        for (key, value) in obj {
            match key.as_ref() {
                "timestamp" => ts = Some(try!(value.as_f64().ok_or("Invalid GELF timestamp"))),
                "host" => {
                    hostname = Some(try!(value.as_str()
                            .ok_or("GELF host name must be a string"))
                        .to_owned())
                }
                "short_message" => {
                    msg = Some(try!(value.as_str().ok_or("GELF short message must be a string"))
                        .to_owned())
                }
                "full_message" => {
                    full_msg = Some(try!(value.as_str()
                            .ok_or("GELF full message must be a string"))
                        .to_owned())
                }
                "version" => {
                    match try!(value.as_str().ok_or("GELF version must be a string")) {
                        "1.0" | "1.1" => {}
                        _ => return Err("Unsupported GELF version"),
                    }
                }
                "level" => {
                    let severity_given = try!(value.as_u64().ok_or("Invalid severity level"));
                    if severity_given > SEVERITY_MAX as u64 {
                        return Err("Invalid severity level (too high)");
                    }
                    severity = Some(severity_given as u8)
                }
                name => {
                    let sd_value: SDValue = match *value {
                        Value::String(ref value) => SDValue::String(value.to_owned()),
                        Value::Bool(value) => SDValue::Bool(value),
                        Value::F64(value) => SDValue::F64(value),
                        Value::I64(value) => SDValue::I64(value),
                        Value::U64(value) => SDValue::U64(value),
                        Value::Null => SDValue::Null,
                        _ => return Err("Invalid value type in structured data"),
                    };
                    let name = if name.starts_with('_') {
                        name.to_owned()
                    } else {
                        format!("_{}", name)
                    };
                    sd.pairs.push((name, sd_value));
                }
            }
        }
        let record = Record {
            ts: ts.unwrap_or_else(|| utils::PreciseTimestamp::now().as_f64()),
            hostname: try!(hostname.ok_or("Missing hostname")),
            facility: None,
            severity: severity,
            appname: None,
            procid: None,
            msgid: None,
            sd: if sd.pairs.is_empty() { None } else { Some(sd) },
            msg: msg,
            full_msg: full_msg,
        };
        Ok(record)
    }
}

#[test]
fn test_gelf() {
    let msg = r#"{"version":"1.1", "host": "example.org","short_message": "A short message that helps you identify what is going on", "full_message": "Backtrace here\n\nmore stuff", "timestamp": 1385053862.3072, "level": 1, "_user_id": 9001, "_some_info": "foo", "_some_env_var": "bar"}"#;
    let res = GelfDecoder.decode(msg).unwrap();
    assert!(res.ts == 1385053862.3072);
    assert!(res.hostname == "example.org");
    assert!(res.msg.unwrap() == "A short message that helps you identify what is going on");
    assert!(res.full_msg.unwrap() == "Backtrace here\n\nmore stuff");
    assert!(res.severity.unwrap() == 1);

    let sd = res.sd.unwrap();
    let pairs = sd.pairs;
    assert!(pairs.iter().cloned().any(|(k, v)| if let SDValue::U64(v) = v {
        k == "_user_id" && v == 9001
    } else {
        false
    }));
    assert!(pairs.iter().cloned().any(|(k, v)| if let SDValue::String(v) = v {
        k == "_some_info" && v == "foo"
    } else {
        false
    }));
    assert!(pairs.iter().cloned().any(|(k, v)| if let SDValue::String(v) = v {
        k == "_some_env_var" && v == "bar"
    } else {
        false
    }));
}
<commit_msg>GELF is not valid JSON. Unescaped \n are allowed in GELF, not JSON.<commit_after>use flowgger::config::Config;
use flowgger::record::{Record, StructuredData, SDValue, SEVERITY_MAX};
use flowgger::utils;
use serde_json::de;
use serde_json::value::Value;
use super::Decoder;

#[derive(Clone)]
pub struct GelfDecoder;

impl GelfDecoder {
    pub fn new(_config: &Config) -> GelfDecoder {
        GelfDecoder
    }
}

impl Decoder for GelfDecoder {
    fn decode(&self, line: &str) -> Result<Record, &'static str> {
        let mut sd = StructuredData::new(None);
        let mut ts = None;
        let mut hostname = None;
        let mut msg = None;
        let mut full_msg = None;
        let mut severity = None;

        let obj: Value = try!(de::from_str(line)
            .or(Err("Invalid GELF input, unable to parse as a JSON object")));
        let obj = try!(obj.as_object().ok_or("Empty GELF input"));
        for (key, value) in obj {
            match key.as_ref() {
                "timestamp" => ts = Some(try!(value.as_f64().ok_or("Invalid GELF timestamp"))),
                "host" => {
                    hostname = Some(try!(value.as_str()
                            .ok_or("GELF host name must be a string"))
                        .to_owned())
                }
                "short_message" => {
                    msg = Some(try!(value.as_str().ok_or("GELF short message must be a string"))
                        .to_owned())
                }
                "full_message" => {
                    full_msg = Some(try!(value.as_str()
                            .ok_or("GELF full message must be a string"))
                        .to_owned())
                }
                "version" => {
                    match try!(value.as_str().ok_or("GELF version must be a string")) {
                        "1.0" | "1.1" => {}
                        _ => return Err("Unsupported GELF version"),
                    }
                }
                "level" => {
                    let severity_given = try!(value.as_u64().ok_or("Invalid severity level"));
                    if severity_given > SEVERITY_MAX as u64 {
                        return Err("Invalid severity level (too high)");
                    }
                    severity = Some(severity_given as u8)
                }
                name => {
                    let sd_value: SDValue = match *value {
                        Value::String(ref value) => SDValue::String(value.to_owned()),
                        Value::Bool(value) => SDValue::Bool(value),
                        Value::F64(value) => SDValue::F64(value),
                        Value::I64(value) => SDValue::I64(value),
                        Value::U64(value) => SDValue::U64(value),
                        Value::Null => SDValue::Null,
                        _ => return Err("Invalid value type in structured data"),
                    };
                    let name = if name.starts_with('_') {
                        name.to_owned()
                    } else {
                        format!("_{}", name)
                    };
                    sd.pairs.push((name, sd_value));
                }
            }
        }
        let record = Record {
            ts: ts.unwrap_or_else(|| utils::PreciseTimestamp::now().as_f64()),
            hostname: try!(hostname.ok_or("Missing hostname")),
            facility: None,
            severity: severity,
            appname: None,
            procid: None,
            msgid: None,
            sd: if sd.pairs.is_empty() { None } else { Some(sd) },
            msg: msg,
            full_msg: full_msg,
        };
        Ok(record)
    }
}

#[test]
fn test_gelf() {
    let msg = r#"{"version":"1.1", "host": "example.org","short_message": "A short message that helps you identify what is going on", "full_message": "Backtrace here\n
more stuff", "timestamp": 1385053862.3072, "level": 1, "_user_id": 9001, "_some_info": "foo", "_some_env_var": "bar"}"#;
    let res = GelfDecoder.decode(msg).unwrap();
    assert!(res.ts == 1385053862.3072);
    assert!(res.hostname == "example.org");
    assert!(res.msg.unwrap() == "A short message that helps you identify what is going on");
    assert!(res.full_msg.unwrap() == "Backtrace here\n\nmore stuff");
    assert!(res.severity.unwrap() == 1);

    let sd = res.sd.unwrap();
    let pairs = sd.pairs;
    assert!(pairs.iter().cloned().any(|(k, v)| if let SDValue::U64(v) = v {
        k == "_user_id" && v == 9001
    } else {
        false
    }));
    assert!(pairs.iter().cloned().any(|(k, v)| if let SDValue::String(v) = v {
        k == "_some_info" && v == "foo"
    } else {
        false
    }));
    assert!(pairs.iter().cloned().any(|(k, v)| if let SDValue::String(v) = v {
        k == "_some_env_var" && v == "bar"
    } else {
        false
    }));
}
<|endoftext|>


<commit_before>use crate::async_runtime;
use crate::config::{Config, EnvConfig};
use crate::error::{Error, ErrorKind, Result};
use crate::git::Git;
use crate::github_api::Client;
use getopts::Options;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::PathBuf;

fn handle_scp_like_syntax(mut url: String) -> String {
    // ref: https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols

    if url.contains("://") {
        // When url is a URL like https://server/project.git
        return url;
    }

    // When the target is an scp-like syntax: [user@]server:project.git
    // Handle ':' in the syntax. Note that GitHub user name may start with number (#24)
    if let Some(i) = url.find(':') {
        let after_colon = i + 1;
        if let Some(i) = url[after_colon..].find(':') {
            // When port number exists
            //  git@service.com:123:user/repo.git -> git@service.com:123/user/repo.git
            let i = after_colon + i;
            url.replace_range(i..i + 1, "/");
        } else {
            // When a port number is omitted, default SSH port is 22
            //  git@service.com:user/repo.git -> git@service.com:22/user/repo.git
            url.insert_str(after_colon, "22/"); // Insert port number after colon
        }
    }

    // Examples:
    //  git@service.com:22/user/repo.git -> ssh://git@service.com:22/user/repo.git
    url.insert_str(0, "ssh://");
    url
}

#[cfg_attr(feature = "cargo-clippy", allow(clippy::large_enum_variant))]
#[derive(Debug)]
pub enum Parsed {
    Help(String),
    Version(&'static str),
    OpenPage(Config),
}

fn is_scp_like_syntax_with_user(s: &str) -> bool {
    // SCP-like syntax like user@project:project
    // user@ cannot be omitted in SCP-like syntax because `s` can be a search query
    //
    // Note that checking it starts with "git@" does not work because SSH protocol for
    // visualstudio.com is "mycompany@vs-ssh.visualstudio.com:v3/project.git"
    if s.contains(char::is_whitespace) {
        return false; // Containing whitespace means it's a search query
    }
    for (i, c) in s.char_indices() {
        match c {
            '@' if i == 0 => return false,          // Seems query like "@rhysd"
            '@' => return s[i + 1..].contains(':'), // SCP-like syntax must also contain ':'
            ':' => return false,                    // '@' must be put before ':'
            _ => continue,
        }
    }
    false
}

fn normalize_repo_format(mut slug: String, env: &EnvConfig) -> Result<String> {
    if slug.is_empty() {
        return Error::err(ErrorKind::BrokenRepoFormat { input: slug });
    }

    // - URL like https://server/project
    // - SCP-like syntax user@project:project
    //
    // Note: user@ cannot be omitted in SCP-like syntax because `slug` can be search word
    if slug.starts_with("https://")
        || slug.starts_with("ssh://")
        || slug.starts_with("http://")
        || slug.starts_with("file://")
        || is_scp_like_syntax_with_user(&slug)
    {
        if !slug.ends_with(".git") {
            slug.push_str(".git");
        }
        return Ok(slug);
    }

    match slug.chars().filter(|c| *c == '/').count() {
        1 => Ok(format!("https://github.com/{}.git", slug)),
        2 => Ok(format!("https://{}.git", slug)),
        0 => {
            let client = Client::build("api.github.com", &env.github_token, &env.https_proxy)?;
            async_runtime::blocking(client.most_popular_repo_by_name(&slug))
                .map(|repo| repo.clone_url)
        }
        _ => Error::err(ErrorKind::BrokenRepoFormat { input: slug }),
    }
}

fn get_cwd(specified: Option<String>) -> Result<PathBuf> {
    if let Some(dir) = specified {
        let p = fs::canonicalize(&dir)?;
        if !p.exists() {
            return Error::err(ErrorKind::SpecifiedDirNotExist { dir });
        }
        Ok(p)
    } else {
        Ok(env::current_dir()?.canonicalize()?)
    }
}

const USAGE: &str = "\
Usage: git brws [Options] {Args}

  Open a repository, file, commit, diff or pull request, issue or project's
  website in your web browser from command line.
  GitHub, Bitbucket, GitLab, GitHub Enterprise, Azure DevOps are supported as
  hosting service.
  git-brws looks some environment variables for configuration. Please see
  https://github.com/rhysd/git-brws#readme for more details.

Examples:
  - Current repository:

    $ git brws

  - GitHub repository:

    $ git brws -r rhysd/git-brws

  - Most popular GitHub repository by name:

    $ git brws -r git-brws

  - File:

    $ git brws some/file.txt

  - Commit:

    $ git brws HEAD~3

  - Tag:

    $ git brws 0.10.0

  - Diff between commits:

    $ git brws HEAD~3..HEAD

  - Diff between topic and topic's merge base commit:

    $ git brws master...topic

  - Line 123 of file:

    $ git brws some/file.txt#L123

  - Range from line 123 to line 126 of file:

    $ git brws some/file.txt#L123-L126

  - Pull request page (for GitHub and GitHub Enterprise):

    $ git brws --pr

  - Website of repository at current directory

    $ git brws --website

  - Website of other repository

    $ git brws --website --repo react

  - Issue page:

    $ git brws '#8'";

impl Parsed {
    pub fn parse_iter<I>(argv: I) -> Result<Parsed>
    where
        I: IntoIterator,
        I::Item: AsRef<OsStr>,
    {
        let mut opts = Options::new();

        opts.optopt("r", "repo", "Shorthand format (repo, user/repo, host/user/repo) or Git URL you want to see. When only repo name is specified, most popular repository will be searched from GitHub", "REPO");
        opts.optopt("b", "branch", "Branch name to browse", "BRANCH");
        opts.optopt(
            "d",
            "dir",
            "Directory path to the repository. Default value is current working directory",
            "PATH",
        );
        opts.optopt("R", "remote", "Remote name (e.g. origin). Default value is a remote the current branch is tracking. If current branch tracks no branch, it falls back to 'origin'", "REMOTE");
        opts.optflag(
            "u",
            "url",
            "Output URL to stdout instead of opening in browser",
        );
        opts.optflag(
            "p",
            "pr",
            "Open pull request page instead of repository page. If not existing, open 'Create Pull Request' page",
        );
        opts.optflag(
            "w",
            "website",
            "Open website page instead of repository page (homepage URL for GitHub, GitLab pages, Bitbucket Cloud)",
        );
        opts.optflag(
            "B",
            "blame",
            "Open blame page instead of repository page. File path to blame must be passed also.",
        );
        opts.optflag("h", "help", "Print this help");
        opts.optflag("v", "version", "Show version");

        let matches = opts.parse(argv.into_iter().skip(1))?;

        if matches.opt_present("h") {
            return Ok(Parsed::Help(opts.usage(USAGE)));
        }

        if matches.opt_present("v") {
            return Ok(Parsed::Version(
                option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
            ));
        }

        let env = EnvConfig::from_iter(env::vars())?.with_global_env();
        let cwd = get_cwd(matches.opt_str("d"))?;
        let branch = matches.opt_str("b");
        let (repo_url, remote) = match (matches.opt_str("r"), matches.opt_str("R")) {
            (Some(repo), remote) => {
                if !matches.free.is_empty() {
                    return Error::err(ErrorKind::ArgsNotAllowed {
                        flag: "--repo {repo}",
                        args: matches.free,
                    });
                }
                (normalize_repo_format(repo, &env)?, remote)
            }
            (None, remote) => {
                let git = Git::new(&cwd, &env.git_command);
                let (url, remote) = if let Some(remote) = remote {
                    (git.remote_url(&remote)?, remote)
                } else {
                    git.tracking_remote_url(&branch)?
                };
                (url, Some(remote))
            }
        };

        let repo_url = handle_scp_like_syntax(repo_url);

        Ok(Parsed::OpenPage(Config {
            repo_url,
            branch,
            cwd,
            stdout: matches.opt_present("u"),
            pull_request: matches.opt_present("p"),
            website: matches.opt_present("w"),
            blame: matches.opt_present("B"),
            args: matches.free,
            remote,
            env,
        }))
    }
}
<commit_msg>add -c flag to open current branch easily<commit_after>use crate::async_runtime;
use crate::config::{Config, EnvConfig};
use crate::error::{Error, ErrorKind, Result};
use crate::git::Git;
use crate::github_api::Client;
use getopts::Options;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::PathBuf;

fn handle_scp_like_syntax(mut url: String) -> String {
    // ref: https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols

    if url.contains("://") {
        // When url is a URL like https://server/project.git
        return url;
    }

    // When the target is an scp-like syntax: [user@]server:project.git
    // Handle ':' in the syntax. Note that GitHub user name may start with number (#24)
    if let Some(i) = url.find(':') {
        let after_colon = i + 1;
        if let Some(i) = url[after_colon..].find(':') {
            // When port number exists
            //  git@service.com:123:user/repo.git -> git@service.com:123/user/repo.git
            let i = after_colon + i;
            url.replace_range(i..i + 1, "/");
        } else {
            // When a port number is omitted, default SSH port is 22
            //  git@service.com:user/repo.git -> git@service.com:22/user/repo.git
            url.insert_str(after_colon, "22/"); // Insert port number after colon
        }
    }

    // Examples:
    //  git@service.com:22/user/repo.git -> ssh://git@service.com:22/user/repo.git
    url.insert_str(0, "ssh://");
    url
}

#[cfg_attr(feature = "cargo-clippy", allow(clippy::large_enum_variant))]
#[derive(Debug)]
pub enum Parsed {
    Help(String),
    Version(&'static str),
    OpenPage(Config),
}

fn is_scp_like_syntax_with_user(s: &str) -> bool {
    // SCP-like syntax like user@project:project
    // user@ cannot be omitted in SCP-like syntax because `s` can be a search query
    //
    // Note that checking it starts with "git@" does not work because SSH protocol for
    // visualstudio.com is "mycompany@vs-ssh.visualstudio.com:v3/project.git"
    if s.contains(char::is_whitespace) {
        return false; // Containing whitespace means it's a search query
    }
    for (i, c) in s.char_indices() {
        match c {
            '@' if i == 0 => return false,          // Seems query like "@rhysd"
            '@' => return s[i + 1..].contains(':'), // SCP-like syntax must also contain ':'
            ':' => return false,                    // '@' must be put before ':'
            _ => continue,
        }
    }
    false
}

fn normalize_repo_format(mut slug: String, env: &EnvConfig) -> Result<String> {
    if slug.is_empty() {
        return Error::err(ErrorKind::BrokenRepoFormat { input: slug });
    }

    // - URL like https://server/project
    // - SCP-like syntax user@project:project
    //
    // Note: user@ cannot be omitted in SCP-like syntax because `slug` can be search word
    if slug.starts_with("https://")
        || slug.starts_with("ssh://")
        || slug.starts_with("http://")
        || slug.starts_with("file://")
        || is_scp_like_syntax_with_user(&slug)
    {
        if !slug.ends_with(".git") {
            slug.push_str(".git");
        }
        return Ok(slug);
    }

    match slug.chars().filter(|c| *c == '/').count() {
        1 => Ok(format!("https://github.com/{}.git", slug)),
        2 => Ok(format!("https://{}.git", slug)),
        0 => {
            let client = Client::build("api.github.com", &env.github_token, &env.https_proxy)?;
            async_runtime::blocking(client.most_popular_repo_by_name(&slug))
                .map(|repo| repo.clone_url)
        }
        _ => Error::err(ErrorKind::BrokenRepoFormat { input: slug }),
    }
}

fn get_cwd(specified: Option<String>) -> Result<PathBuf> {
    if let Some(dir) = specified {
        let p = fs::canonicalize(&dir)?;
        if !p.exists() {
            return Error::err(ErrorKind::SpecifiedDirNotExist { dir });
        }
        Ok(p)
    } else {
        Ok(env::current_dir()?.canonicalize()?)
    }
}

const USAGE: &str = "\
Usage: git brws [Options] {Args}

  Open a repository, file, commit, diff or pull request, issue or project's
  website in your web browser from command line.
  GitHub, Bitbucket, GitLab, GitHub Enterprise, Azure DevOps are supported as
  hosting service.
  git-brws looks some environment variables for configuration. Please see
  https://github.com/rhysd/git-brws#readme for more details.

Examples:
  - Current repository:

    $ git brws

  - GitHub repository:

    $ git brws -r rhysd/git-brws

  - Most popular GitHub repository by name:

    $ git brws -r git-brws

  - File:

    $ git brws some/file.txt

  - Commit:

    $ git brws HEAD~3

  - Tag:

    $ git brws 0.10.0

  - Diff between commits:

    $ git brws HEAD~3..HEAD

  - Diff between topic and topic's merge base commit:

    $ git brws master...topic

  - Line 123 of file:

    $ git brws some/file.txt#L123

  - Range from line 123 to line 126 of file:

    $ git brws some/file.txt#L123-L126

  - Pull request page (for GitHub and GitHub Enterprise):

    $ git brws --pr

  - Website of repository at current directory

    $ git brws --website

  - Website of other repository

    $ git brws --website --repo react

  - Issue page:

    $ git brws '#8'";

impl Parsed {
    pub fn parse_iter<I>(argv: I) -> Result<Parsed>
    where
        I: IntoIterator,
        I::Item: AsRef<OsStr>,
    {
        let mut opts = Options::new();

        opts.optopt("r", "repo", "Shorthand format (repo, user/repo, host/user/repo) or Git URL you want to see. When only repo name is specified, most popular repository will be searched from GitHub", "REPO");
        opts.optopt("b", "branch", "Branch name to browse", "BRANCH");
        opts.optopt(
            "d",
            "dir",
            "Directory path to the repository. Default value is current working directory",
            "PATH",
        );
        opts.optopt("R", "remote", "Remote name (e.g. origin). Default value is a remote the current branch is tracking. If current branch tracks no branch, it falls back to 'origin'", "REMOTE");
        opts.optflag(
            "u",
            "url",
            "Output URL to stdout instead of opening in browser",
        );
        opts.optflag(
            "p",
            "pr",
            "Open pull request page instead of repository page. If not existing, open 'Create Pull Request' page",
        );
        opts.optflag(
            "w",
            "website",
            "Open website page instead of repository page (homepage URL for GitHub, GitLab pages, Bitbucket Cloud)",
        );
        opts.optflag(
            "B",
            "blame",
            "Open blame page instead of repository page. File path to blame must be passed also.",
        );
        opts.optflag(
            "c",
            "current-branch",
            "Open the current branch instead of default branch",
        );
        opts.optflag("h", "help", "Print this help");
        opts.optflag("v", "version", "Show version");

        let matches = opts.parse(argv.into_iter().skip(1))?;

        if matches.opt_present("h") {
            return Ok(Parsed::Help(opts.usage(USAGE)));
        }

        if matches.opt_present("v") {
            return Ok(Parsed::Version(
                option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
            ));
        }

        let env = EnvConfig::from_iter(env::vars())?.with_global_env();
        let cwd = get_cwd(matches.opt_str("d"))?;
        let git = Git::new(&cwd, &env.git_command);
        let branch = if let Some(b) = matches.opt_str("b") {
            Some(b)
        } else if matches.opt_present("c") {
            Some(git.current_branch()?)
        } else {
            None
        };
        let (repo_url, remote) = match (matches.opt_str("r"), matches.opt_str("R")) {
            (Some(repo), remote) => {
                if !matches.free.is_empty() {
                    return Error::err(ErrorKind::ArgsNotAllowed {
                        flag: "--repo {repo}",
                        args: matches.free,
                    });
                }
                (normalize_repo_format(repo, &env)?, remote)
            }
            (None, remote) => {
                let (url, remote) = if let Some(remote) = remote {
                    (git.remote_url(&remote)?, remote)
                } else {
                    git.tracking_remote_url(&branch)?
                };
                (url, Some(remote))
            }
        };

        let repo_url = handle_scp_like_syntax(repo_url);

        Ok(Parsed::OpenPage(Config {
            repo_url,
            branch,
            cwd,
            stdout: matches.opt_present("u"),
            pull_request: matches.opt_present("p"),
            website: matches.opt_present("w"),
            blame: matches.opt_present("B"),
            args: matches.free,
            remote,
            env,
        }))
    }
}
<|endoftext|>