<commit_before>use Renderable;
use context::Context;
use std::collections::HashMap;
use std::cmp::Ordering;
use error::{Result, Error};
use token::Token;
use token::Token::*;

/// An enum to represent different value types
#[derive(Clone, Debug)]
pub enum Value {
    Num(f32),
    Str(String),
    Object(HashMap<String, Value>),
    Array(Vec<Value>),
    Bool(bool),
}

impl Value {
    /// Shorthand function to create Value::Str from a string slice.
    pub fn str(val: &str) -> Value {
        Value::Str(val.to_owned())
    }

    /// Parses a token that can possibly represent a Value
    /// to said Value. Returns an Err if the token can not
    /// be interpreted as a Value.
    pub fn from_token(t: &Token) -> Result<Value> {
        match t {
            &StringLiteral(ref x) => Ok(Value::Str(x.to_owned())),
            &NumberLiteral(x) => Ok(Value::Num(x)),
            &BooleanLiteral(x) => Ok(Value::Bool(x)),
            x => Error::parser("Value", Some(x)),
        }
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x == y,
            (&Value::Str(ref x), &Value::Str(ref y)) => x == y,
            (&Value::Bool(x), &Value::Bool(y)) => x == y,
            (&Value::Object(ref x), &Value::Object(ref y)) => x == y,
            (&Value::Array(ref x), &Value::Array(ref y)) => x == y,

            // encode Ruby truthiness; all values except false and nil
            // are true, and we don't have a notion of nil
            (_, &Value::Bool(b)) |
            (&Value::Bool(b), _) => b,

            _ => false,
        }
    }
}

// TODO implement for object and array
// TODO clean this up
impl PartialOrd<Value> for Value {
    fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.partial_cmp(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.partial_cmp(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.partial_cmp(&y),
            _ => None,
        }
    }
    fn lt(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.lt(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.lt(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.lt(&y),
            _ => false,
        }
    }
    fn le(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.le(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.le(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.le(&y),
            _ => false,
        }
    }
    fn gt(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.gt(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.gt(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.gt(&y),
            _ => false,
        }
    }
    fn ge(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.ge(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.ge(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.ge(&y),
            _ => false,
        }
    }
}

impl ToString for Value {
    fn to_string(&self) -> String {
        match *self {
            Value::Bool(ref x) => x.to_string(),
            Value::Num(ref x) => x.to_string(),
            Value::Str(ref x) => x.to_owned(),
            Value::Array(ref x) => {
                let arr: Vec<String> = x.iter().map(|v| v.to_string()).collect();
                arr.join(", ")
            }
            Value::Object(ref x) => {
                let arr: Vec<String> =
                    x.iter().map(|(k, v)| k.clone() + ": " + &v.to_string()).collect();
                arr.join(", ")
            }
        }
    }
}

impl Renderable for Value {
    fn render(&self, _context: &mut Context) -> Result<Option<String>> {
        Ok(Some(self.to_string()))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;

    static TRUE: Value = Value::Bool(true);
    static FALSE: Value = Value::Bool(false);

    #[test]
    fn test_num_to_string() {
        let val = Value::Num(42f32);
        assert_eq!(&val.to_string(), "42");

        let val = Value::Num(42.34);
        assert_eq!(&val.to_string(), "42.34");
    }

    #[test]
    fn test_str_to_string() {
        let val = Value::Str("foobar".to_owned());
        assert_eq!(&val.to_string(), "foobar");
    }

    #[test]
    fn test_array_to_string() {
        let val =
            Value::Array(vec![Value::Num(3f32), Value::Str("test".to_owned()), Value::Num(5.3)]);
        assert_eq!(&val.to_string(), "3, test, 5.3");
    }

    // TODO make a test for object, remember values are in arbitrary orders in HashMaps

    #[test]
    fn boolean_equality() {
        assert_eq!(Value::Bool(true), Value::Bool(true));
        assert_eq!(Value::Bool(false), Value::Bool(false));
        assert!(Value::Bool(false) != Value::Bool(true));
        assert!(Value::Bool(true) != Value::Bool(false));
    }

    #[test]
    fn booleans_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Bool(true));
        assert_eq!(FALSE, Value::Bool(false));
    }

    #[test]
    fn string_equality() {
        assert_eq!(Value::str("alpha"), Value::str("alpha"));
        assert_eq!(Value::str(""), Value::str(""));
        assert!(Value::str("alpha") != Value::str("beta"));
        assert!(Value::str("beta") != Value::str("alpha"));
    }

    #[test]
    fn strings_have_ruby_truthiness() {
        // all strings in ruby are true
        assert_eq!(TRUE, Value::str("All strings are truthy"));
        assert_eq!(TRUE, Value::str(""));
    }

    #[test]
    fn number_equality() {
        assert_eq!(Value::Num(42f32), Value::Num(42f32));
        assert_eq!(Value::Num(0f32), Value::Num(0f32));
        assert!(Value::Num(1f32) != Value::Num(2f32));
        assert!(Value::Num(2f32) != Value::Num(1f32));
    }

    #[test]
    fn numbers_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Num(42f32));
        assert_eq!(TRUE, Value::Num(0f32));
    }

    #[test]
    fn object_equality() {
        let mut values = HashMap::<String, Value>::new();
        values.insert("alpha".to_owned(), Value::str("1"));
        values.insert("beta".to_owned(), Value::Num(2f32));

        let a = Value::Object(values.clone());

        values.insert("gamma".to_owned(), Value::Array(vec![]));
        let b = Value::Object(values);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn objects_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Object(HashMap::new()));
    }

    #[test]
    fn array_equality() {
        let a = Value::Array(vec![Value::str("one"), Value::str("two")]);
        let b = Value::Array(vec![Value::str("alpha"), Value::str("beta")]);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn arrays_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Array(Vec::new()));
    }

    #[test]
    fn mixed_comparisons_are_false() {
        // assers that all comparisons between different types of values
        // are false
        let mut values = HashMap::<String, Value>::new();
        values.insert("alpha".to_owned(), Value::str("1"));

        let terms = vec![Value::Num(1f32),
                         Value::str("1"),
                         Value::Object(values),
                         Value::Array(vec![Value::Num(1f32)])];

        for (x, a) in terms.iter().enumerate() {
            for (y, b) in terms.iter().enumerate() {
                if x != y {
                    assert!(a != b);
                    assert!(b != a);
                }
            }
        }
    }
}
<commit_msg>Add as_str for Value<commit_after>use Renderable;
use context::Context;
use std::collections::HashMap;
use std::cmp::Ordering;
use error::{Result, Error};
use token::Token;
use token::Token::*;

/// An enum to represent different value types
#[derive(Clone, Debug)]
pub enum Value {
    Num(f32),
    Str(String),
    Object(HashMap<String, Value>),
    Array(Vec<Value>),
    Bool(bool),
}

impl<'a> Value {
    /// Shorthand function to create Value::Str from a string slice.
    pub fn str(val: &str) -> Value {
        Value::Str(val.to_owned())
    }

    pub fn as_str(&'a self) -> Option<&'a str> {
        match *self {
            Value::Str(ref v) => Some(v),
            _ => None,
        }
    }

    /// Parses a token that can possibly represent a Value
    /// to said Value. Returns an Err if the token can not
    /// be interpreted as a Value.
    pub fn from_token(t: &Token) -> Result<Value> {
        match t {
            &StringLiteral(ref x) => Ok(Value::Str(x.to_owned())),
            &NumberLiteral(x) => Ok(Value::Num(x)),
            &BooleanLiteral(x) => Ok(Value::Bool(x)),
            x => Error::parser("Value", Some(x)),
        }
    }
}

impl PartialEq<Value> for Value {
    fn eq(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x == y,
            (&Value::Str(ref x), &Value::Str(ref y)) => x == y,
            (&Value::Bool(x), &Value::Bool(y)) => x == y,
            (&Value::Object(ref x), &Value::Object(ref y)) => x == y,
            (&Value::Array(ref x), &Value::Array(ref y)) => x == y,

            // encode Ruby truthiness; all values except false and nil
            // are true, and we don't have a notion of nil
            (_, &Value::Bool(b)) |
            (&Value::Bool(b), _) => b,

            _ => false,
        }
    }
}

// TODO implement for object and array
// TODO clean this up
impl PartialOrd<Value> for Value {
    fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.partial_cmp(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.partial_cmp(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.partial_cmp(&y),
            _ => None,
        }
    }
    fn lt(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.lt(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.lt(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.lt(&y),
            _ => false,
        }
    }
    fn le(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.le(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.le(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.le(&y),
            _ => false,
        }
    }
    fn gt(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.gt(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.gt(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.gt(&y),
            _ => false,
        }
    }
    fn ge(&self, other: &Value) -> bool {
        match (self, other) {
            (&Value::Num(x), &Value::Num(y)) => x.ge(&y),
            (&Value::Str(ref x), &Value::Str(ref y)) => x.ge(y),
            (&Value::Bool(x), &Value::Bool(y)) => x.ge(&y),
            _ => false,
        }
    }
}

impl ToString for Value {
    fn to_string(&self) -> String {
        match *self {
            Value::Bool(ref x) => x.to_string(),
            Value::Num(ref x) => x.to_string(),
            Value::Str(ref x) => x.to_owned(),
            Value::Array(ref x) => {
                let arr: Vec<String> = x.iter().map(|v| v.to_string()).collect();
                arr.join(", ")
            }
            Value::Object(ref x) => {
                let arr: Vec<String> =
                    x.iter().map(|(k, v)| k.clone() + ": " + &v.to_string()).collect();
                arr.join(", ")
            }
        }
    }
}

impl Renderable for Value {
    fn render(&self, _context: &mut Context) -> Result<Option<String>> {
        Ok(Some(self.to_string()))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::HashMap;

    static TRUE: Value = Value::Bool(true);
    static FALSE: Value = Value::Bool(false);

    #[test]
    fn test_as_str() {
        let val = Value::Num(42f32);
        assert_eq!(val.as_str(), None);

        let val = Value::str("test");
        assert_eq!(val.as_str(), Some("test"));
    }

    #[test]
    fn test_num_to_string() {
        let val = Value::Num(42f32);
        assert_eq!(&val.to_string(), "42");

        let val = Value::Num(42.34);
        assert_eq!(&val.to_string(), "42.34");
    }

    #[test]
    fn test_str_to_string() {
        let val = Value::Str("foobar".to_owned());
        assert_eq!(&val.to_string(), "foobar");
    }

    #[test]
    fn test_array_to_string() {
        let val =
            Value::Array(vec![Value::Num(3f32), Value::Str("test".to_owned()), Value::Num(5.3)]);
        assert_eq!(&val.to_string(), "3, test, 5.3");
    }

    // TODO make a test for object, remember values are in arbitrary orders in HashMaps

    #[test]
    fn boolean_equality() {
        assert_eq!(Value::Bool(true), Value::Bool(true));
        assert_eq!(Value::Bool(false), Value::Bool(false));
        assert!(Value::Bool(false) != Value::Bool(true));
        assert!(Value::Bool(true) != Value::Bool(false));
    }

    #[test]
    fn booleans_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Bool(true));
        assert_eq!(FALSE, Value::Bool(false));
    }

    #[test]
    fn string_equality() {
        assert_eq!(Value::str("alpha"), Value::str("alpha"));
        assert_eq!(Value::str(""), Value::str(""));
        assert!(Value::str("alpha") != Value::str("beta"));
        assert!(Value::str("beta") != Value::str("alpha"));
    }

    #[test]
    fn strings_have_ruby_truthiness() {
        // all strings in ruby are true
        assert_eq!(TRUE, Value::str("All strings are truthy"));
        assert_eq!(TRUE, Value::str(""));
    }

    #[test]
    fn number_equality() {
        assert_eq!(Value::Num(42f32), Value::Num(42f32));
        assert_eq!(Value::Num(0f32), Value::Num(0f32));
        assert!(Value::Num(1f32) != Value::Num(2f32));
        assert!(Value::Num(2f32) != Value::Num(1f32));
    }

    #[test]
    fn numbers_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Num(42f32));
        assert_eq!(TRUE, Value::Num(0f32));
    }

    #[test]
    fn object_equality() {
        let mut values = HashMap::<String, Value>::new();
        values.insert("alpha".to_owned(), Value::str("1"));
        values.insert("beta".to_owned(), Value::Num(2f32));

        let a = Value::Object(values.clone());

        values.insert("gamma".to_owned(), Value::Array(vec![]));
        let b = Value::Object(values);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn objects_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Object(HashMap::new()));
    }

    #[test]
    fn array_equality() {
        let a = Value::Array(vec![Value::str("one"), Value::str("two")]);
        let b = Value::Array(vec![Value::str("alpha"), Value::str("beta")]);

        assert_eq!(a, a);
        assert!(a != b);
        assert!(b != a);
    }

    #[test]
    fn arrays_have_ruby_truthiness() {
        assert_eq!(TRUE, Value::Array(Vec::new()));
    }

    #[test]
    fn mixed_comparisons_are_false() {
        // assers that all comparisons between different types of values
        // are false
        let mut values = HashMap::<String, Value>::new();
        values.insert("alpha".to_owned(), Value::str("1"));

        let terms = vec![Value::Num(1f32),
                         Value::str("1"),
                         Value::Object(values),
                         Value::Array(vec![Value::Num(1f32)])];

        for (x, a) in terms.iter().enumerate() {
            for (y, b) in terms.iter().enumerate() {
                if x != y {
                    assert!(a != b);
                    assert!(b != a);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::collections::hash_map;
use std::ops::Range;
use time;

use cgmath;
use cgmath::{BaseNum, Point3};
use collision::{Aabb3, Line2};

use perlin;

pub type Block = Point3<i32>;

// Has to be odd since (0, 0, 0) is at the center of a chunk.
pub const CHUNK_SIZE: i32 = 17;

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Chunk(Point3<i32>);

impl Chunk {
  pub fn new(x: i32, y: i32, z: i32) -> Chunk {
    Chunk(Point3 {
      x: x,
      y: y,
      z: z,
    })
  }

  pub fn block_bounds(&self) -> Aabb3<i32> {
    let center = Point3 {
      x: self.0.x * CHUNK_SIZE,
      y: self.0.y * CHUNK_SIZE,
      z: self.0.z * CHUNK_SIZE,
    };
    let half_chunk = (CHUNK_SIZE - 1) / 2;
    Aabb3 {
      min: Point3 {
        x: center.x - half_chunk,
        y: center.y - half_chunk,
        z: center.z - half_chunk,
      },
      max: Point3 {
        x: center.x + half_chunk,
        y: center.y + half_chunk,
        z: center.z + half_chunk,
      }
    }
  }
}

/// World model 𝓦.
pub struct World {
  /// All blocks in the world.
  blocks: HashSet<Block>,
  /// Blocks divided by chunk they belong to.
  chunk_blocks: HashMap<Chunk, Vec<Block>>,
  /// Eye coordinates.
  eye: Option<Point3<i32>>,
}

/// 2 dimensional point on xz plane.
#[derive(Clone, Debug)]
pub struct Point2<T> {
  pub x: T,
  pub z: T,
}

impl <T> Point2<T> {
  pub fn new(x: T, z: T) -> Point2<T> {
    Point2 {
      x: x,
      z: z,
    }
  }
}

impl <T: BaseNum> Point2<T> {
  pub fn as_cgmath(&self) -> cgmath::Point2<T> {
    cgmath::Point2::new(self.x, self.z)
  }
}

/// 2 dimensional segment on xz plane.
#[derive(Debug)]
pub struct Segment2<T> {
  pub start: Point2<T>,
  pub end: Point2<T>,
}

impl <T> Segment2<T> {
  pub fn new(start: Point2<T>, end: Point2<T>) -> Segment2<T> {
    Segment2 {
      start: start,
      end: end,
    }
  }
}

impl Segment2<i32> {
  pub fn as_cgmath(&self) -> Line2<f32> {
    let origin = cgmath::Point2::new(self.start.x as f32, self.start.z as f32);
    let dest = cgmath::Point2::new(self.end.x as f32, self.end.z as f32);
    Line2::new(origin, dest)
  }
}

/// 2 dimensional rectangle on xz plane.
#[derive(Debug)]
struct Rect2<T> {
  min: Point2<T>,
  max: Point2<T>,
}

impl Rect2<i32> {
  fn x_range(&self) -> Range<i32> {
    Range {
      start: self.min.x,
      // Important: +1 since the end is exclusive.
      end: self.max.x + 1,
    }
  }

  fn z_range(&self) -> Range<i32> {
    Range {
      start: self.min.z,
      // Important: +1 since the end is exclusive.
      end: self.max.z + 1,
    }
  }
}

impl World {
  /// Generates world chunks visible from the start point within the radius.
  pub fn new(start: &Point2<f32>, radius: f32) -> World {
    let start_s = time::precise_time_s();
    log!("*** Generating world...");

    let xz_chunk_rect = start_radius_to_chunk_rect(start, radius);

    let mut chunks: Vec<Point2<i32>> = Vec::new();
    for x_chunk in xz_chunk_rect.x_range() {
      for z_chunk in xz_chunk_rect.z_range() {
        let chunk = Point2::new(x_chunk, z_chunk);
        if within_radius(start, radius, &chunk) {
          chunks.push(chunk);
        }
      }
    }
    let chunks = &chunks;

    let mut all_blocks: HashSet<Block> = HashSet::new();
    let mut chunk_blocks: HashMap<Chunk, Vec<Block>> = HashMap::with_capacity(chunks.len());
    for c in chunks {
      let chunk_3d = Chunk::new(c.x, 0, c.z);
      let block_bounds = chunk_3d.block_bounds();
      let blocks = perlin::generate_blocks(&block_bounds);

      all_blocks.extend(blocks.clone());
      chunk_blocks.insert(chunk_3d, blocks);
    }

    let eye = {
      let chunk0_blocks = chunk_blocks.get(&Chunk::new(0, 0, 0)).unwrap();
      let start_block = Point2 {
        x: coord_to_block(start.x),
        z: coord_to_block(start.z),
      };
      place_eye(&chunk0_blocks, &start_block)
    };

    let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
    log!("*** Generated world: {:.3}ms, {} chunks, {} blocks", spent_ms, chunk_blocks.len(), all_blocks.len());

    World {
      blocks: all_blocks,
      chunk_blocks: chunk_blocks,
      eye: eye,
    }
  }

  #[inline]
  pub fn len(&self) -> usize {
    self.blocks.len()
  }

  #[inline]
  pub fn chunk_blocks(&self) -> hash_map::Iter<Chunk, Vec<Block>> {
    self.chunk_blocks.iter()
  }

  #[inline]
  pub fn contains(&self, block: &Block) -> bool {
    self.blocks.contains(block)
  }

  #[inline]
  pub fn eye(&self) -> Option<Point3<i32>> {
    self.eye
  }
}

fn start_radius_to_chunk_rect(start: &Point2<f32>, radius: f32) -> Rect2<i32> {
  Rect2 {
    min: Point2 {
      x: coord_to_chunk(start.x - radius),
      z: coord_to_chunk(start.z - radius),
    },
    max: Point2 {
      x: coord_to_chunk(start.x + radius),
      z: coord_to_chunk(start.z + radius),
    },
  }
}

#[inline]
fn coord_to_chunk(coord: f32) -> i32 {
  (coord / CHUNK_SIZE as f32).round() as i32
}

#[inline]
fn coord_to_block(coord: f32) -> i32 {
  coord.round() as i32
}

fn within_radius(center: &Point2<f32>, radius: f32, chunk: &Point2<i32>) -> bool {
  let vertices = rect_to_vertices(&chunk_rect(chunk));
  let radius_squared = radius * radius;
  let within_radius_vertex = |v: &Point2<f32>| -> bool {
    distance_squared(v, center) <= radius_squared
  };
  within_radius_vertex(&vertices[0]) || within_radius_vertex(&vertices[1]) ||
    within_radius_vertex(&vertices[2]) || within_radius_vertex(&vertices[3])
}

fn chunk_rect(chunk: &Point2<i32>) -> Rect2<f32> {
  let center = Point2 {
    x: chunk.x * CHUNK_SIZE,
    z: chunk.z * CHUNK_SIZE,
  };

  let half_chunk = 0.5 * CHUNK_SIZE as f32;
  Rect2 {
    min: Point2 {
      x: center.x as f32 - half_chunk,
      z: center.z as f32 - half_chunk,
    },
    max: Point2 {
      x: center.x as f32 + half_chunk,
      z: center.z as f32 + half_chunk,
    }
  }
}

fn rect_to_vertices(rect: &Rect2<f32>) -> [Point2<f32>; 4] {
  [
    Point2::new(rect.min.x, rect.min.z),
    Point2::new(rect.max.x, rect.min.z),
    Point2::new(rect.min.x, rect.max.z),
    Point2::new(rect.max.x, rect.max.z),
  ]
}

fn distance_squared(p1: &Point2<f32>, p2: &Point2<f32>) -> f32 {
  (p1.x - p2.x) * (p1.x - p2.x) + (p1.z - p2.z) * (p1.z - p2.z)
}

/// Place the eye on top of the highest block: max {y: (xz.x, y, xz.z) ∈ 𝓦}
fn place_eye(blocks: &Vec<Block>, xz: &Point2<i32>) -> Option<Point3<i32>> {
  let y_of_matching_xz = |b: &Block| -> Option<i32> {
    if b.x == xz.z && b.z == xz.x {
      Some(b.y)
    } else {
      None
    }
  };
  let max_y = blocks.iter().filter_map(|&b| y_of_matching_xz(&b)).max();
  max_y.map(|y| {
    log!("*** Placed eye at: ({}, {}, {})", xz.x, y, xz.z);
    Point3::new(xz.x, y, xz.z)
  })
}

#[cfg(test)]
mod tests {
  use std::ops::Not;
  use super::{CHUNK_SIZE, Point2, coord_to_chunk, within_radius};

  #[test]
  fn coord_to_chunk_test_center_0() {
    assert_eq!(coord_to_chunk(0.0), 0)
  }

  #[test]
  fn coord_to_chunk_test_center_pos_1() {
    assert_eq!(coord_to_chunk(CHUNK_SIZE as f32), 1)
  }

  #[test]
  fn coord_to_chunk_test_center_neg_1() {
    assert_eq!(coord_to_chunk(-CHUNK_SIZE as f32), -1)
  }

  #[test]
  fn coord_to_chunk_test_center_pos_half() {
    assert_eq!(coord_to_chunk(CHUNK_SIZE as f32 * 0.5), 1)
  }

  #[test]
  fn coord_to_chunk_test_center_neg_half() {
    assert_eq!(coord_to_chunk(-CHUNK_SIZE as f32 * 0.5), -1)
  }

  #[test]
  fn within_radius_test_yes() {
    assert!(within_radius(&Point2::new(0.0, 0.0), CHUNK_SIZE as f32, &Point2::new(1, 1)));
  }

  #[test]
  fn within_radius_test_no() {
    assert!(within_radius(&Point2::new(0.0, 0.0), CHUNK_SIZE as f32 * 0.5, &Point2::new(0, 1)).not());
  }
}
<commit_msg>Refactor: Extract within_radius_iter.<commit_after>use std::collections::{HashMap, HashSet};
use std::collections::hash_map;
use time;

use cgmath;
use cgmath::{BaseNum, Point3};
use collision::{Aabb3, Line2};

use perlin;

pub type Block = Point3<i32>;

// Has to be odd since (0, 0, 0) is at the center of a chunk.
pub const CHUNK_SIZE: i32 = 17;

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Chunk(Point3<i32>);

impl Chunk {
  pub fn new(x: i32, y: i32, z: i32) -> Chunk {
    Chunk(Point3 {
      x: x,
      y: y,
      z: z,
    })
  }

  pub fn block_bounds(&self) -> Aabb3<i32> {
    let center = Point3 {
      x: self.0.x * CHUNK_SIZE,
      y: self.0.y * CHUNK_SIZE,
      z: self.0.z * CHUNK_SIZE,
    };
    let half_chunk = (CHUNK_SIZE - 1) / 2;
    Aabb3 {
      min: Point3 {
        x: center.x - half_chunk,
        y: center.y - half_chunk,
        z: center.z - half_chunk,
      },
      max: Point3 {
        x: center.x + half_chunk,
        y: center.y + half_chunk,
        z: center.z + half_chunk,
      }
    }
  }
}

/// World model 𝓦.
pub struct World {
  /// All blocks in the world.
  blocks: HashSet<Block>,
  /// Blocks divided by chunk they belong to.
  chunk_blocks: HashMap<Chunk, Vec<Block>>,
  /// Eye coordinates.
  eye: Option<Point3<i32>>,
}

/// 2 dimensional point on xz plane.
#[derive(Clone, Debug)]
pub struct Point2<T> {
  pub x: T,
  pub z: T,
}

impl <T> Point2<T> {
  pub fn new(x: T, z: T) -> Point2<T> {
    Point2 {
      x: x,
      z: z,
    }
  }
}

impl <T: BaseNum> Point2<T> {
  pub fn as_cgmath(&self) -> cgmath::Point2<T> {
    cgmath::Point2::new(self.x, self.z)
  }
}

/// 2 dimensional segment on xz plane.
#[derive(Debug)]
pub struct Segment2<T> {
  pub start: Point2<T>,
  pub end: Point2<T>,
}

impl <T> Segment2<T> {
  pub fn new(start: Point2<T>, end: Point2<T>) -> Segment2<T> {
    Segment2 {
      start: start,
      end: end,
    }
  }
}

impl Segment2<i32> {
  pub fn as_cgmath(&self) -> Line2<f32> {
    let origin = cgmath::Point2::new(self.start.x as f32, self.start.z as f32);
    let dest = cgmath::Point2::new(self.end.x as f32, self.end.z as f32);
    Line2::new(origin, dest)
  }
}

/// 2 dimensional rectangle on xz plane.
#[derive(Debug)]
struct Rect2<T> {
  min: Point2<T>,
  max: Point2<T>,
}

impl World {
  /// Generates world chunks visible from the start point within the radius.
  pub fn new(start: &Point2<f32>, radius: f32) -> World {
    let start_s = time::precise_time_s();
    log!("*** Generating world...");

    // TODO: Load the chunk at (0, 0, 0) synchronously, load other chunks within radius in the
    // background, while prioritizing chunks in the field of view.
    let mut all_blocks: HashSet<Block> = HashSet::new();
    assert!(radius > 0.0);
    let capacity_estimate = radius as usize * radius as usize;
    let mut chunk_blocks: HashMap<Chunk, Vec<Block>> = HashMap::with_capacity(capacity_estimate);

    let eye = {
      let chunk0 = Chunk::new(0, 0, 0);
      let blocks0 = perlin::generate_blocks(&chunk0.block_bounds());
      all_blocks.extend(blocks0.clone());
      chunk_blocks.insert(chunk0, blocks0.clone());

      let start_block = Point2 {
        x: coord_to_block(start.x),
        z: coord_to_block(start.z),
      };
      place_eye(&blocks0, &start_block)
    };

    for c in within_radius_iter(start, radius) {
      let blocks = perlin::generate_blocks(&c.block_bounds());
      all_blocks.extend(blocks.clone());
      chunk_blocks.insert(c, blocks);
    }

    let spent_ms = (time::precise_time_s() - start_s) * 1000.0;
    log!("*** Generated world: {:.3}ms, {} chunks, {} blocks", spent_ms, chunk_blocks.len(), all_blocks.len());

    World {
      blocks: all_blocks,
      chunk_blocks: chunk_blocks,
      eye: eye,
    }
  }

  #[inline]
  pub fn len(&self) -> usize {
    self.blocks.len()
  }

  #[inline]
  pub fn chunk_blocks(&self) -> hash_map::Iter<Chunk, Vec<Block>> {
    self.chunk_blocks.iter()
  }

  #[inline]
  pub fn contains(&self, block: &Block) -> bool {
    self.blocks.contains(block)
  }

  #[inline]
  pub fn eye(&self) -> Option<Point3<i32>> {
    self.eye
  }
}

struct WithinRadiusIterator {
  start: Point2<f32>,
  radius: f32,
  min_x: i32,
  next_x: i32,
  end_x: i32,
  next_z: i32,
  end_z: i32,
}

/// Returns chunks within given radius of the start point, except for chunk (0, 0, 0).
// Darn, have to hand-code this, there is no way to create ranges and filter_map
// them to return an iterator.
fn within_radius_iter(start: &Point2<f32>, radius: f32) -> WithinRadiusIterator {
  let min_x = coord_to_chunk(start.x - radius);
  let max_x = coord_to_chunk(start.z + radius);
  let min_z = coord_to_chunk(start.z - radius);
  let max_z = coord_to_chunk(start.z + radius);
  WithinRadiusIterator {
    start: start.clone(),
    radius: radius,
    min_x: min_x,
    next_x: min_x,
    end_x: max_x + 1,
    next_z: min_z,
    end_z: max_z + 1,
  }
}

impl WithinRadiusIterator {
  fn skip_chunk(&self) -> bool {
    if self.next_x == 0 && self.next_z == 0 {
      return true;
    }
    let chunk = Point2::new(self.next_x, self.next_z);
    !within_radius(&self.start, self.radius, &chunk)
  }

  fn inc(&mut self) -> () {
    if self.next_x < self.end_x {
      self.next_x += 1;
    } else {
      self.next_x = self.min_x;
      self.next_z += 1;
    }
  }
}

impl Iterator for WithinRadiusIterator {
  type Item = Chunk;
  fn next(&mut self) -> Option<Chunk> {
    while self.next_x < self.end_x && self.next_z < self.end_z {
      if self.skip_chunk() {
        self.inc();
        continue;
      }
      let result = Some(Chunk::new(self.next_x, 0, self.next_z));
      self.inc();
      return result;
    }
    None
  }
}

#[inline]
fn coord_to_chunk(coord: f32) -> i32 {
  (coord / CHUNK_SIZE as f32).round() as i32
}

#[inline]
fn coord_to_block(coord: f32) -> i32 {
  coord.round() as i32
}

fn within_radius(center: &Point2<f32>, radius: f32, chunk: &Point2<i32>) -> bool {
  let vertices = rect_to_vertices(&chunk_rect(chunk));
  let radius_squared = radius * radius;
  let within_radius_vertex = |v: &Point2<f32>| -> bool {
    distance_squared(v, center) <= radius_squared
  };
  within_radius_vertex(&vertices[0]) || within_radius_vertex(&vertices[1]) ||
    within_radius_vertex(&vertices[2]) || within_radius_vertex(&vertices[3])
}

fn chunk_rect(chunk: &Point2<i32>) -> Rect2<f32> {
  let center = Point2 {
    x: chunk.x * CHUNK_SIZE,
    z: chunk.z * CHUNK_SIZE,
  };

  let half_chunk = 0.5 * CHUNK_SIZE as f32;
  Rect2 {
    min: Point2 {
      x: center.x as f32 - half_chunk,
      z: center.z as f32 - half_chunk,
    },
    max: Point2 {
      x: center.x as f32 + half_chunk,
      z: center.z as f32 + half_chunk,
    }
  }
}

fn rect_to_vertices(rect: &Rect2<f32>) -> [Point2<f32>; 4] {
  [
    Point2::new(rect.min.x, rect.min.z),
    Point2::new(rect.max.x, rect.min.z),
    Point2::new(rect.min.x, rect.max.z),
    Point2::new(rect.max.x, rect.max.z),
  ]
}

fn distance_squared(p1: &Point2<f32>, p2: &Point2<f32>) -> f32 {
  (p1.x - p2.x) * (p1.x - p2.x) + (p1.z - p2.z) * (p1.z - p2.z)
}

/// Place the eye on top of the highest block: max {y: (xz.x, y, xz.z) ∈ 𝓦}
fn place_eye(blocks: &Vec<Block>, xz: &Point2<i32>) -> Option<Point3<i32>> {
  let y_of_matching_xz = |b: &Block| -> Option<i32> {
    if b.x == xz.z && b.z == xz.x {
      Some(b.y)
    } else {
      None
    }
  };
  let max_y = blocks.iter().filter_map(|&b| y_of_matching_xz(&b)).max();
  max_y.map(|y| {
    log!("*** Placed eye at: ({}, {}, {})", xz.x, y, xz.z);
    Point3::new(xz.x, y, xz.z)
  })
}

#[cfg(test)]
mod tests {
  use std::ops::Not;
  use super::{CHUNK_SIZE, Point2, coord_to_chunk, within_radius};

  #[test]
  fn coord_to_chunk_test_center_0() {
    assert_eq!(coord_to_chunk(0.0), 0)
  }

  #[test]
  fn coord_to_chunk_test_center_pos_1() {
    assert_eq!(coord_to_chunk(CHUNK_SIZE as f32), 1)
  }

  #[test]
  fn coord_to_chunk_test_center_neg_1() {
    assert_eq!(coord_to_chunk(-CHUNK_SIZE as f32), -1)
  }

  #[test]
  fn coord_to_chunk_test_center_pos_half() {
    assert_eq!(coord_to_chunk(CHUNK_SIZE as f32 * 0.5), 1)
  }

  #[test]
  fn coord_to_chunk_test_center_neg_half() {
    assert_eq!(coord_to_chunk(-CHUNK_SIZE as f32 * 0.5), -1)
  }

  #[test]
  fn within_radius_test_yes() {
    assert!(within_radius(&Point2::new(0.0, 0.0), CHUNK_SIZE as f32, &Point2::new(1, 1)));
  }

  #[test]
  fn within_radius_test_no() {
    assert!(within_radius(&Point2::new(0.0, 0.0), CHUNK_SIZE as f32 * 0.5, &Point2::new(0, 1)).not());
  }
}
<|endoftext|>


<commit_before>use consts::LINK_CONTROL_BYTES;
use util::slice_u24;

use trunking::fields::{
    TalkGroup,
    ServiceOptions,
};

pub type Buf = [u8; LINK_CONTROL_BYTES];

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum LinkControlOpcode {
    GroupVoiceTraffic,
    GroupVoiceUpdate,
    UnitVoiceTraffic,
    GroupVoiceUpdateExplicit,
    UnitVoiceRequest,
    PhoneVoiceTraffic,
    PhoneVoiceRequest,
    CallTermination,
    GroupAffiliationQuery,
    UnitRegistrationRequest,
    UnitAuthenticationRequst,
    UnitStatusRequest,
    SystemServiceBroadcast,
    AltControlChannel,
    AdjacentSite,
    RFSSStatusBroadcast,
    NetworkStatusBroadcast,
    UnitStatusUpdate,
    UnitShortMessage,
    UnitCallAlert,
    ExtendedFunction,
    ChannelParamsUpdate,
    ProtectionParamBroadcast,
    AltControlChannelExplicit,
    AdjacentSiteExplicit,
    ChannelParamsExplicit,
    RFSSStatusExplicit,
    NetworkStatusExplicit,
}

impl LinkControlOpcode {
    pub fn from_bits(bits: u8) -> Option<LinkControlOpcode> {
        use self::LinkControlOpcode::*;

        match bits {
            0b000000 => Some(GroupVoiceTraffic),
            0b000010 => Some(GroupVoiceUpdate),
            0b000011 => Some(UnitVoiceTraffic),
            0b000100 => Some(GroupVoiceUpdateExplicit),
            0b000101 => Some(UnitVoiceRequest),
            0b000110 => Some(PhoneVoiceTraffic),
            0b000111 => Some(PhoneVoiceRequest),
            0b001111 => Some(CallTermination),
            0b010000 => Some(GroupAffiliationQuery),
            0b010001 => Some(UnitRegistrationRequest),
            0b010010 => Some(UnitAuthenticationRequst),
            0b010011 => Some(UnitStatusRequest),
            0b100000 => Some(SystemServiceBroadcast),
            0b100001 => Some(AltControlChannel),
            0b100010 => Some(AdjacentSite),
            0b100011 => Some(RFSSStatusBroadcast),
            0b100100 => Some(NetworkStatusBroadcast),
            0b010100 => Some(UnitStatusUpdate),
            0b010101 => Some(UnitShortMessage),
            0b010110 => Some(UnitCallAlert),
            0b010111 => Some(ExtendedFunction),
            0b011000 => Some(ChannelParamsUpdate),
            0b100101 => Some(ProtectionParamBroadcast),
            0b100110 => Some(AltControlChannelExplicit),
            0b100111 => Some(AdjacentSiteExplicit),
            0b011001 => Some(ChannelParamsExplicit),
            0b101000 => Some(RFSSStatusExplicit),
            0b101001 => Some(NetworkStatusExplicit),
            _ => None,
        }
    }
}

/// Link Control information carried within voice packets.
#[derive(Copy, Clone)]
pub struct LinkControlFields(Buf);

impl LinkControlFields {
    /// Interpret the given bytes as a link control packet.
    pub fn new(buf: Buf) -> Self { LinkControlFields(buf) }

    /// Whether the packet is encrypted.
    pub fn protected(&self) -> bool { self.0[0] >> 7 == 1 }

    /// Type of data contained in the payload.
    pub fn opcode(&self) -> Option<LinkControlOpcode> {
        LinkControlOpcode::from_bits(self.0[0] & 0x3F)
    }

    /// Bytes that make up the payload.
    pub fn payload(&self) -> &[u8] { &self.0[1...8] }
}

pub struct GroupVoiceTraffic(Buf);

impl GroupVoiceTraffic {
    pub fn new(lc: LinkControlFields) -> Self { GroupVoiceTraffic(lc.0) }

    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[6..]) }
}

pub struct UnitVoiceTraffic(Buf);

impl UnitVoiceTraffic {
    pub fn new(lc: LinkControlFields) -> Self { UnitVoiceTraffic(lc.0) }

    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[3..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[6..]) }
}

pub struct CallTermination(Buf);

impl CallTermination {
    pub fn new(lc: LinkControlFields) -> Self { CallTermination(lc.0) }
    pub fn unit(&self) -> u32 { slice_u24(&self.0[6..]) }
}

#[cfg(test)]
mod test {
    use super::*;
    use trunking::fields::{TalkGroup, AdjacentSite, GroupVoiceUpdate};

    #[test]
    fn test_lc() {
        let lc = LinkControlFields::new([
            0b00000000,
            0b00000000,
            0b10110101, 0b00000000,
            0b00000000, 0b00000001,
            0xDE, 0xAD, 0xBE,
        ]);

        assert_eq!(lc.opcode(), Some(LinkControlOpcode::GroupVoiceTraffic));
        assert_eq!(lc.protected(), false);

        assert_eq!(lc.payload(), &[
            0b00000000,
            0b10110101, 0b00000000,
            0b00000000, 0b00000001,
            0xDE, 0xAD, 0xBE,
        ]);
    }

    #[test]
    fn test_adjacent_site() {
        let lc = LinkControlFields::new([
            0b10100111,
            0b11001100,
            0b00001111,
            0b01010101,
            0b11100011,
            0b00011000,
            0b11000001,
            0b11111111,
            0b01010001,
        ]);
        let a = AdjacentSite::new(lc.payload());

        assert_eq!(a.area(), 0b11001100);
        assert_eq!(a.system(), 0b111101010101);
        assert_eq!(a.rfss(), 0b11100011);
        assert_eq!(a.site(), 0b00011000);
        assert_eq!(a.channel().id(), 0b1100);
        assert_eq!(a.channel().number(), 0b000111111111);
        let s = a.services();
        assert!(s.is_composite());
        assert!(!s.has_updates());
        assert!(!s.is_backup());
        assert!(s.has_data());
        assert!(!s.has_voice());
        assert!(s.has_registration());
        assert!(!s.has_auth());
    }

    #[test]
    fn test_group_voice_traffic() {
        let lc = LinkControlFields::new([
            0b00000000,
            0b00000000,
            0b10110101, 0b00000000,
            0b00000000, 0b00000001,
            0xDE, 0xAD, 0xBE,
        ]);

        let dec = GroupVoiceTraffic::new(lc);
        let opts = dec.opts();

        assert_eq!(dec.mfg(), 0);
        assert_eq!(dec.talk_group(), TalkGroup::Default);
        assert_eq!(dec.src_unit(), 0xDEADBE);

        assert_eq!(opts.emergency(), true);
        assert_eq!(opts.protected(), false);
        assert_eq!(opts.duplex(), true);
        assert_eq!(opts.packet_switched(), true);
        assert_eq!(opts.prio(), 5);
    }

    #[test]
    fn test_group_voice_update() {
        let l = LinkControlFields::new([
            0b00000010,
            0b01101111,
            0b01010101,
            0b11111111,
            0b11111111,
            0b10011010,
            0b10101010,
            0b00110011,
            0b11001100,
        ]);
        let u = GroupVoiceUpdate::new(l.payload()).updates();

        assert_eq!(u[0].0.id(), 0b0110);
        assert_eq!(u[0].0.number(), 0b111101010101);
        assert_eq!(u[0].1, TalkGroup::Everbody);
        assert_eq!(u[1].0.id(), 0b1001);
        assert_eq!(u[1].0.number(), 0b101010101010);
        assert_eq!(u[1].1, TalkGroup::Other(0b0011001111001100));
    }
}
<commit_msg>Add voice ChannelParamsUpdate test<commit_after>use consts::LINK_CONTROL_BYTES;
use util::slice_u24;

use trunking::fields::{
    TalkGroup,
    ServiceOptions,
};

pub type Buf = [u8; LINK_CONTROL_BYTES];

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum LinkControlOpcode {
    GroupVoiceTraffic,
    GroupVoiceUpdate,
    UnitVoiceTraffic,
    GroupVoiceUpdateExplicit,
    UnitVoiceRequest,
    PhoneVoiceTraffic,
    PhoneVoiceRequest,
    CallTermination,
    GroupAffiliationQuery,
    UnitRegistrationRequest,
    UnitAuthenticationRequst,
    UnitStatusRequest,
    SystemServiceBroadcast,
    AltControlChannel,
    AdjacentSite,
    RFSSStatusBroadcast,
    NetworkStatusBroadcast,
    UnitStatusUpdate,
    UnitShortMessage,
    UnitCallAlert,
    ExtendedFunction,
    ChannelParamsUpdate,
    ProtectionParamBroadcast,
    AltControlChannelExplicit,
    AdjacentSiteExplicit,
    ChannelParamsExplicit,
    RFSSStatusExplicit,
    NetworkStatusExplicit,
}

impl LinkControlOpcode {
    pub fn from_bits(bits: u8) -> Option<LinkControlOpcode> {
        use self::LinkControlOpcode::*;

        match bits {
            0b000000 => Some(GroupVoiceTraffic),
            0b000010 => Some(GroupVoiceUpdate),
            0b000011 => Some(UnitVoiceTraffic),
            0b000100 => Some(GroupVoiceUpdateExplicit),
            0b000101 => Some(UnitVoiceRequest),
            0b000110 => Some(PhoneVoiceTraffic),
            0b000111 => Some(PhoneVoiceRequest),
            0b001111 => Some(CallTermination),
            0b010000 => Some(GroupAffiliationQuery),
            0b010001 => Some(UnitRegistrationRequest),
            0b010010 => Some(UnitAuthenticationRequst),
            0b010011 => Some(UnitStatusRequest),
            0b100000 => Some(SystemServiceBroadcast),
            0b100001 => Some(AltControlChannel),
            0b100010 => Some(AdjacentSite),
            0b100011 => Some(RFSSStatusBroadcast),
            0b100100 => Some(NetworkStatusBroadcast),
            0b010100 => Some(UnitStatusUpdate),
            0b010101 => Some(UnitShortMessage),
            0b010110 => Some(UnitCallAlert),
            0b010111 => Some(ExtendedFunction),
            0b011000 => Some(ChannelParamsUpdate),
            0b100101 => Some(ProtectionParamBroadcast),
            0b100110 => Some(AltControlChannelExplicit),
            0b100111 => Some(AdjacentSiteExplicit),
            0b011001 => Some(ChannelParamsExplicit),
            0b101000 => Some(RFSSStatusExplicit),
            0b101001 => Some(NetworkStatusExplicit),
            _ => None,
        }
    }
}

/// Link Control information carried within voice packets.
#[derive(Copy, Clone)]
pub struct LinkControlFields(Buf);

impl LinkControlFields {
    /// Interpret the given bytes as a link control packet.
    pub fn new(buf: Buf) -> Self { LinkControlFields(buf) }

    /// Whether the packet is encrypted.
    pub fn protected(&self) -> bool { self.0[0] >> 7 == 1 }

    /// Type of data contained in the payload.
    pub fn opcode(&self) -> Option<LinkControlOpcode> {
        LinkControlOpcode::from_bits(self.0[0] & 0x3F)
    }

    /// Bytes that make up the payload.
    pub fn payload(&self) -> &[u8] { &self.0[1...8] }
}

pub struct GroupVoiceTraffic(Buf);

impl GroupVoiceTraffic {
    pub fn new(lc: LinkControlFields) -> Self { GroupVoiceTraffic(lc.0) }

    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn talk_group(&self) -> TalkGroup { TalkGroup::new(&self.0[4..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[6..]) }
}

pub struct UnitVoiceTraffic(Buf);

impl UnitVoiceTraffic {
    pub fn new(lc: LinkControlFields) -> Self { UnitVoiceTraffic(lc.0) }

    pub fn mfg(&self) -> u8 { self.0[1] }
    pub fn opts(&self) -> ServiceOptions { ServiceOptions::new(self.0[2]) }
    pub fn dest_unit(&self) -> u32 { slice_u24(&self.0[3..]) }
    pub fn src_unit(&self) -> u32 { slice_u24(&self.0[6..]) }
}

pub struct CallTermination(Buf);

impl CallTermination {
    pub fn new(lc: LinkControlFields) -> Self { CallTermination(lc.0) }
    pub fn unit(&self) -> u32 { slice_u24(&self.0[6..]) }
}

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

    #[test]
    fn test_lc() {
        let lc = LinkControlFields::new([
            0b00000000,
            0b00000000,
            0b10110101, 0b00000000,
            0b00000000, 0b00000001,
            0xDE, 0xAD, 0xBE,
        ]);

        assert_eq!(lc.opcode(), Some(LinkControlOpcode::GroupVoiceTraffic));
        assert_eq!(lc.protected(), false);

        assert_eq!(lc.payload(), &[
            0b00000000,
            0b10110101, 0b00000000,
            0b00000000, 0b00000001,
            0xDE, 0xAD, 0xBE,
        ]);
    }

    #[test]
    fn test_adjacent_site() {
        let lc = LinkControlFields::new([
            0b10100111,
            0b11001100,
            0b00001111,
            0b01010101,
            0b11100011,
            0b00011000,
            0b11000001,
            0b11111111,
            0b01010001,
        ]);
        let a = AdjacentSite::new(lc.payload());

        assert_eq!(a.area(), 0b11001100);
        assert_eq!(a.system(), 0b111101010101);
        assert_eq!(a.rfss(), 0b11100011);
        assert_eq!(a.site(), 0b00011000);
        assert_eq!(a.channel().id(), 0b1100);
        assert_eq!(a.channel().number(), 0b000111111111);
        let s = a.services();
        assert!(s.is_composite());
        assert!(!s.has_updates());
        assert!(!s.is_backup());
        assert!(s.has_data());
        assert!(!s.has_voice());
        assert!(s.has_registration());
        assert!(!s.has_auth());
    }

    #[test]
    fn test_group_voice_traffic() {
        let lc = LinkControlFields::new([
            0b00000000,
            0b00000000,
            0b10110101, 0b00000000,
            0b00000000, 0b00000001,
            0xDE, 0xAD, 0xBE,
        ]);

        let dec = GroupVoiceTraffic::new(lc);
        let opts = dec.opts();

        assert_eq!(dec.mfg(), 0);
        assert_eq!(dec.talk_group(), TalkGroup::Default);
        assert_eq!(dec.src_unit(), 0xDEADBE);

        assert_eq!(opts.emergency(), true);
        assert_eq!(opts.protected(), false);
        assert_eq!(opts.duplex(), true);
        assert_eq!(opts.packet_switched(), true);
        assert_eq!(opts.prio(), 5);
    }

    #[test]
    fn test_channel_params_update() {
        let l = LinkControlFields::new([
            0b00011000,
            0b01100011,
            0b00100010,
            0b11010000,
            0b00110010,
            0b00001010,
            0b00100101,
            0b00010000,
            0b10100010,
        ]);
        let p = ChannelParamsUpdate::new(l.payload());

        assert_eq!(p.id(), 0b0110);
        assert_eq!(p.params().bandwidth, 12_500);
        assert_eq!(p.params().rx_freq(0b1001), 851_062_500);
    }

    #[test]
    fn test_group_voice_update() {
        let l = LinkControlFields::new([
            0b00000010,
            0b01101111,
            0b01010101,
            0b11111111,
            0b11111111,
            0b10011010,
            0b10101010,
            0b00110011,
            0b11001100,
        ]);
        let u = GroupVoiceUpdate::new(l.payload()).updates();

        assert_eq!(u[0].0.id(), 0b0110);
        assert_eq!(u[0].0.number(), 0b111101010101);
        assert_eq!(u[0].1, TalkGroup::Everbody);
        assert_eq!(u[1].0.id(), 0b1001);
        assert_eq!(u[1].0.number(), 0b101010101010);
        assert_eq!(u[1].1, TalkGroup::Other(0b0011001111001100));
    }
}
<|endoftext|>


<commit_before>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature, PushOptions, RemoteCallbacks, Cred};

use commit_analyzer::{self, CommitType};
use error::Error;
use config::Config;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(config: &Config, message: &str) -> Result<(), git2::Error> {
    let update_ref = format!("refs/heads/{}", config.branch);
    let repo = &config.repository;

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(Some(&update_ref), &config.signature, &config.signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(config: &Config, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let repo = &config.repository;

    let rev = format!("refs/heads/{}", config.branch);
    let obj = try!(repo.revparse_single(&rev));

    repo.tag(tag_name, &obj, &config.signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(repo: &Repository) -> Option<Version> {
    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(repo: &Repository) -> CommitType {
    match latest_tag(repo) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(repo, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(repo: &Repository, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown)
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(config: &Config, new_version: &str) -> Result<(), Error> {
    let repo = &config.repository;
    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&config.repository, &files[..]));

    commit(config, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(config: &Config, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    create_tag(config, &tag_name, &tag_message)
        .map_err(Error::from)
}

pub fn push(config: &Config, tag_name: &str) -> Result<(), Error> {
    let repo      = &config.repository;
    let token     = &config.gh_token.as_ref().unwrap();

    let user      = &config.user.as_ref().unwrap();
    let repo_name = &config.repository_name.as_ref().unwrap();
    let branch    = &config.branch;

    // We need to push both the branch we just committed as well as the tag we created.
    let branch_ref = format!("refs/heads/{}", branch);
    let tag_ref    = format!("refs/tags/{}", tag_name);
    let refs = [&branch_ref[..], &tag_ref[..]];

    let url = format!("https://github.com/{}/{}.git", user, repo_name);

    let mut remote = try!(repo.remote_anonymous(&url));

    let mut cbs = RemoteCallbacks::new();
    cbs.credentials(|_url, _username, _allowed| {
        Cred::userpass_plaintext(&token, "")
    });
    let mut opts = PushOptions::new();
    opts.remote_callbacks(cbs);

    remote
        .push(&refs, Some(&mut opts))
        .map(|_| ())
        .map_err(Error::from)
}
<commit_msg>refactor: remove unnecessary reference operator<commit_after>use std::path::Path;
use semver::Version;
use std::env;
use git2::{self, Repository, Commit, Signature, PushOptions, RemoteCallbacks, Cred};

use commit_analyzer::{self, CommitType};
use error::Error;
use config::Config;

pub fn get_signature(repo: &Repository) -> Result<Signature, Error> {
    let author = {
        let mut author = env::var("GIT_COMMITTER_NAME").map_err(Error::from);

        if author.is_err() {
            let config = try!(repo.config());
            author = config.get_string("user.name").map_err(Error::from);
        }
        try!(author)
    };

    let email = {
        let mut email = env::var("GIT_COMMITTER_EMAIL").map_err(Error::from);

        if email.is_err() {
            let config = try!(repo.config());
            email = config.get_string("user.email").map_err(Error::from);
        }
        try!(email)
    };

    Signature::now(&author, &email).map_err(From::from)
}

fn range_to_head(commit: &str) -> String {
    format!("{}..HEAD", commit)
}

fn format_commit(commit: Commit) -> String {
    format!("{}\n{}", commit.id(), commit.message().unwrap_or(""))
}

fn add<P: AsRef<Path>>(repo: &Repository, files: &[P]) -> Result<(), git2::Error> {
    let mut index = try!(repo.index());

    for path in files {
        try!(index.add_path(path.as_ref()));
    }

    index.write()
}

fn commit(config: &Config, message: &str) -> Result<(), git2::Error> {
    let update_ref = format!("refs/heads/{}", config.branch);
    let repo = &config.repository;

    let oid = try!(repo.refname_to_id("HEAD"));
    let parent_commit = try!(repo.find_commit(oid));
    let parents = vec![&parent_commit];

    let mut index = try!(repo.index());
    let tree_oid = try!(index.write_tree());
    let tree = try!(repo.find_tree(tree_oid));

    repo
        .commit(Some(&update_ref), &config.signature, &config.signature, message, &tree, &parents)
        .map(|_| ())
}

fn create_tag(config: &Config, tag_name: &str, message: &str) -> Result<(), git2::Error> {
    let repo = &config.repository;

    let rev = format!("refs/heads/{}", config.branch);
    let obj = try!(repo.revparse_single(&rev));

    repo.tag(tag_name, &obj, &config.signature, message, false)
        .map(|_| ())
}

pub fn latest_tag(repo: &Repository) -> Option<Version> {
    let tags = match repo.tag_names(None) {
        Ok(tags) => tags,
        Err(_) => return None
    };

    tags.iter()
        .map(|tag| tag.unwrap())
        .filter_map(|tag| Version::parse(&tag[1..]).ok())
        .max()
}

pub fn version_bump_since_latest(repo: &Repository) -> CommitType {
    match latest_tag(repo) {
        Some(t) => {
            let tag = format!("v{}", t.to_string());
            version_bump_since_tag(repo, &tag)
        },
        None => CommitType::Major
    }
}

pub fn version_bump_since_tag(repo: &Repository, tag: &str) -> CommitType {
    let tag = range_to_head(tag);

    let mut walker = repo.revwalk().expect("Creating a revwalk failed");
    walker.push_range(&tag).expect("Adding a range failed");

    walker.map(|c| repo.find_commit(c.expect("Not a valid commit")).expect("No commit found"))
        .map(format_commit)
        .map(|c| commit_analyzer::analyze_single(&c).expect("Analyzing commit failed"))
        .max().unwrap_or(CommitType::Unknown)
}

pub fn generate_commit_message(new_version: &str) -> String {
    format!("Bump version to {}", new_version).into()
}

pub fn commit_files(config: &Config, new_version: &str) -> Result<(), Error> {
    let repo = &config.repository;
    let files = ["Cargo.toml", "Cargo.lock", "Changelog.md"];
    let files = files.iter().filter(|filename| {
        let path = Path::new(filename);
        !repo.status_should_ignore(path).expect("Determining ignore status of file failed")
    }).collect::<Vec<_>>();

    try!(add(&config.repository, &files[..]));

    commit(config, &generate_commit_message(new_version)).map_err(Error::from)
}

pub fn tag(config: &Config, tag_name: &str, tag_message: &str) -> Result<(), Error> {
    create_tag(config, &tag_name, &tag_message)
        .map_err(Error::from)
}

pub fn push(config: &Config, tag_name: &str) -> Result<(), Error> {
    let repo      = &config.repository;
    let token     = config.gh_token.as_ref().unwrap();

    let user      = config.user.as_ref().unwrap();
    let repo_name = config.repository_name.as_ref().unwrap();
    let branch    = &config.branch;

    // We need to push both the branch we just committed as well as the tag we created.
    let branch_ref = format!("refs/heads/{}", branch);
    let tag_ref    = format!("refs/tags/{}", tag_name);
    let refs = [&branch_ref[..], &tag_ref[..]];

    let url = format!("https://github.com/{}/{}.git", user, repo_name);

    let mut remote = try!(repo.remote_anonymous(&url));

    let mut cbs = RemoteCallbacks::new();
    cbs.credentials(|_url, _username, _allowed| {
        Cred::userpass_plaintext(&token, "")
    });
    let mut opts = PushOptions::new();
    opts.remote_callbacks(cbs);

    remote
        .push(&refs, Some(&mut opts))
        .map(|_| ())
        .map_err(Error::from)
}
<|endoftext|>


<commit_before>/* Copyright 2017 Mozilla Foundation
 *
 * 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.
 */

//! A simple event-driven library for parsing WebAssembly binary files
//! (or streams).
//!
//! The parser library reports events as they happend and only stores
//! parsing information for a brief period of time, making it very fast
//! and memory-efficient. The event-driven model, however, has some drawbacks.
//! If you need random access to the entire WebAssembly data-structure,
//! this is not the right library for you. You could however, build such
//! a data-structure using this library.

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]

#[cfg(not(feature = "std"))]
extern crate hashmap_core;

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;

pub use binary_reader::BinaryReader;
pub use binary_reader::Range;
use binary_reader::SectionHeader;

pub use parser::LocalName;
pub use parser::NameEntry;
pub use parser::Parser;
pub use parser::ParserInput;
pub use parser::ParserState;
pub use parser::RelocEntry;
pub use parser::WasmDecoder;

pub use primitives::BinaryReaderError;
pub use primitives::BrTable;
pub use primitives::CustomSectionKind;
pub use primitives::ExternalKind;
pub use primitives::FuncType;
pub use primitives::GlobalType;
pub use primitives::Ieee32;
pub use primitives::Ieee64;
pub use primitives::ImportSectionEntryType;
pub use primitives::LinkingType;
pub use primitives::MemoryImmediate;
pub use primitives::MemoryType;
pub use primitives::NameType;
pub use primitives::Naming;
pub use primitives::Operator;
pub use primitives::RelocType;
pub use primitives::ResizableLimits;
pub use primitives::Result;
pub use primitives::SectionCode;
pub use primitives::TableType;
pub use primitives::Type;

pub use validator::validate;
pub use validator::OperatorValidatorConfig;
pub use validator::ValidatingOperatorParser;
pub use validator::ValidatingParser;
pub use validator::WasmModuleResources;

pub use readers::CodeSectionReader;
pub use readers::Data;
pub use readers::DataSectionReader;
pub use readers::Element;
pub use readers::ElementItems;
pub use readers::ElementItemsReader;
pub use readers::ElementSectionReader;
pub use readers::Export;
pub use readers::ExportSectionReader;
pub use readers::FunctionBody;
pub use readers::FunctionSectionReader;
pub use readers::Global;
pub use readers::GlobalSectionReader;
pub use readers::Import;
pub use readers::ImportSectionReader;
pub use readers::InitExpr;
pub use readers::LinkingSectionReader;
pub use readers::LocalsReader;
pub use readers::MemorySectionReader;
pub use readers::ModuleReader;
pub use readers::Name;
pub use readers::NameSectionReader;
pub use readers::NamingReader;
pub use readers::OperatorsReader;
pub use readers::Reloc;
pub use readers::RelocSectionReader;
pub use readers::Section;
pub use readers::SectionIterator;
pub use readers::SectionIteratorLimited;
pub use readers::SectionReader;
pub use readers::SectionWithLimitedItems;
pub use readers::TableSectionReader;
pub use readers::TypeSectionReader;

mod binary_reader;
mod limits;
mod parser;
mod primitives;
mod readers;
mod tests;
mod validator;

#[cfg(not(feature = "std"))]
mod std {
    pub use alloc::{boxed, vec};
    pub use core::*;
    pub mod collections {
        pub use hashmap_core::HashSet;
    }
}
<commit_msg>Export ValidatingParserConfig too.<commit_after>/* Copyright 2017 Mozilla Foundation
 *
 * 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.
 */

//! A simple event-driven library for parsing WebAssembly binary files
//! (or streams).
//!
//! The parser library reports events as they happend and only stores
//! parsing information for a brief period of time, making it very fast
//! and memory-efficient. The event-driven model, however, has some drawbacks.
//! If you need random access to the entire WebAssembly data-structure,
//! this is not the right library for you. You could however, build such
//! a data-structure using this library.

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), feature(alloc))]

#[cfg(not(feature = "std"))]
extern crate hashmap_core;

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;

pub use binary_reader::BinaryReader;
pub use binary_reader::Range;
use binary_reader::SectionHeader;

pub use parser::LocalName;
pub use parser::NameEntry;
pub use parser::Parser;
pub use parser::ParserInput;
pub use parser::ParserState;
pub use parser::RelocEntry;
pub use parser::WasmDecoder;

pub use primitives::BinaryReaderError;
pub use primitives::BrTable;
pub use primitives::CustomSectionKind;
pub use primitives::ExternalKind;
pub use primitives::FuncType;
pub use primitives::GlobalType;
pub use primitives::Ieee32;
pub use primitives::Ieee64;
pub use primitives::ImportSectionEntryType;
pub use primitives::LinkingType;
pub use primitives::MemoryImmediate;
pub use primitives::MemoryType;
pub use primitives::NameType;
pub use primitives::Naming;
pub use primitives::Operator;
pub use primitives::RelocType;
pub use primitives::ResizableLimits;
pub use primitives::Result;
pub use primitives::SectionCode;
pub use primitives::TableType;
pub use primitives::Type;

pub use validator::validate;
pub use validator::OperatorValidatorConfig;
pub use validator::ValidatingOperatorParser;
pub use validator::ValidatingParser;
pub use validator::ValidatingParserConfig;
pub use validator::WasmModuleResources;

pub use readers::CodeSectionReader;
pub use readers::Data;
pub use readers::DataSectionReader;
pub use readers::Element;
pub use readers::ElementItems;
pub use readers::ElementItemsReader;
pub use readers::ElementSectionReader;
pub use readers::Export;
pub use readers::ExportSectionReader;
pub use readers::FunctionBody;
pub use readers::FunctionSectionReader;
pub use readers::Global;
pub use readers::GlobalSectionReader;
pub use readers::Import;
pub use readers::ImportSectionReader;
pub use readers::InitExpr;
pub use readers::LinkingSectionReader;
pub use readers::LocalsReader;
pub use readers::MemorySectionReader;
pub use readers::ModuleReader;
pub use readers::Name;
pub use readers::NameSectionReader;
pub use readers::NamingReader;
pub use readers::OperatorsReader;
pub use readers::Reloc;
pub use readers::RelocSectionReader;
pub use readers::Section;
pub use readers::SectionIterator;
pub use readers::SectionIteratorLimited;
pub use readers::SectionReader;
pub use readers::SectionWithLimitedItems;
pub use readers::TableSectionReader;
pub use readers::TypeSectionReader;

mod binary_reader;
mod limits;
mod parser;
mod primitives;
mod readers;
mod tests;
mod validator;

#[cfg(not(feature = "std"))]
mod std {
    pub use alloc::{boxed, vec};
    pub use core::*;
    pub mod collections {
        pub use hashmap_core::HashSet;
    }
}
<|endoftext|>


<commit_before>extern crate ascii;

mod pascal_str;
mod pascal_string;

const PASCAL_STRING_BUF_SIZE: usize = 255;

pub use pascal_str::{Chars, CharsMut, PascalStr};
pub use pascal_string::{PascalString, PascalStringAppendError, PascalStringCreateError, AsciiError};

#[cfg(test)]
mod tests {
    use super::*;
    use ascii::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};

    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());
    }

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8);
        string.push('l');
        string.push(AsciiChar::L);
        string.push('o');
        string.push(AsciiChar::Null);

        println!("{}", string);
        assert_eq!(string.as_str(), "heLlLo\0");
    }

    #[test]
    fn test_string_append() {
        let mut string = PascalString::new();
        string.push_str("Hola, ");
        string.push_str("Senor!");
        assert_eq!(string.as_str(), "Hola, Senor!");
    }

    #[test]
    fn test_string_indexing_and_char_iteration() {
        let mut string = PascalString::from("q").unwrap();
        assert_eq!(string[0u8], AsciiChar::q);

        let mut string2 = PascalString::from("WASD").unwrap();
        let mut iter = string2.chars();
        assert_eq!(iter.next(), Some(&AsciiChar::W));
        assert_eq!(iter.next(), Some(&AsciiChar::A));
        assert_eq!(iter.next(), Some(&AsciiChar::S));
        assert_eq!(iter.next(), Some(&AsciiChar::D));
    }

    #[test]
    fn test_as_cstr() {
        let msg = "I am your favourite cookie monster >:-)\0";
        let pstr = PascalString::from(&msg).unwrap();
        let cstr = CStr::from_bytes_with_nul(msg.as_bytes()).unwrap();
        let pstr_as_cstr = pstr.as_cstr().unwrap();
        assert!(match pstr_as_cstr {
            Cow::Borrowed(_) => true,
            _ => false
        });
        assert_eq!(&*pstr_as_cstr, cstr);

        let oversized = ['l'; 255];
        let mut string_oversized = {
            let mut s = String::new();
            for i in 0..oversized.len() {
                s.push(oversized[i]);
            }
            s
        };
        let pstr_oversized = PascalString::from_fixed_ascii_array(255, oversized).unwrap();
        println!("oversized: {}", pstr_oversized.is_full());
        let cstr_from_pstr_oversized = pstr_oversized.as_cstr().unwrap();
        let cstr_from_string_oversized = CString::new(string_oversized).unwrap();
        assert!(match cstr_from_pstr_oversized {
            Cow::Owned(_) => true,
            _ => false
        });
        assert_eq!(cstr_from_pstr_oversized.into_owned(), cstr_from_string_oversized);
    }
}
<commit_msg>Add a test to check what happens when you construct a string from too much data.<commit_after>extern crate ascii;

mod pascal_str;
mod pascal_string;

const PASCAL_STRING_BUF_SIZE: usize = 255;

pub use pascal_str::{Chars, CharsMut, PascalStr};
pub use pascal_string::{PascalString, PascalStringAppendError, PascalStringCreateError, AsciiError};

#[cfg(test)]
mod tests {
    use super::*;
    use ascii::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};

    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());

        let too_many_bytes = vec![12u8; 256];
        assert!(match PascalString::from(&too_many_bytes) {
            Err(PascalStringCreateError::InputTooLong) => true,
            _ => false
        });
    }

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8);
        string.push('l');
        string.push(AsciiChar::L);
        string.push('o');
        string.push(AsciiChar::Null);

        println!("{}", string);
        assert_eq!(string.as_str(), "heLlLo\0");
    }

    #[test]
    fn test_string_append() {
        let mut string = PascalString::new();
        string.push_str("Hola, ");
        string.push_str("Senor!");
        assert_eq!(string.as_str(), "Hola, Senor!");
    }

    #[test]
    fn test_string_indexing_and_char_iteration() {
        let mut string = PascalString::from("q").unwrap();
        assert_eq!(string[0u8], AsciiChar::q);

        let mut string2 = PascalString::from("WASD").unwrap();
        let mut iter = string2.chars();
        assert_eq!(iter.next(), Some(&AsciiChar::W));
        assert_eq!(iter.next(), Some(&AsciiChar::A));
        assert_eq!(iter.next(), Some(&AsciiChar::S));
        assert_eq!(iter.next(), Some(&AsciiChar::D));
    }

    #[test]
    fn test_as_cstr() {
        let msg = "I am your favourite cookie monster >:-)\0";
        let pstr = PascalString::from(&msg).unwrap();
        let cstr = CStr::from_bytes_with_nul(msg.as_bytes()).unwrap();
        let pstr_as_cstr = pstr.as_cstr().unwrap();
        assert!(match pstr_as_cstr {
            Cow::Borrowed(_) => true,
            _ => false
        });
        assert_eq!(&*pstr_as_cstr, cstr);

        let oversized = ['l'; 255];
        let mut string_oversized = {
            let mut s = String::new();
            for i in 0..oversized.len() {
                s.push(oversized[i]);
            }
            s
        };
        let pstr_oversized = PascalString::from_fixed_ascii_array(255, oversized).unwrap();
        println!("oversized: {}", pstr_oversized.is_full());
        let cstr_from_pstr_oversized = pstr_oversized.as_cstr().unwrap();
        let cstr_from_string_oversized = CString::new(string_oversized).unwrap();
        assert!(match cstr_from_pstr_oversized {
            Cow::Owned(_) => true,
            _ => false
        });
        assert_eq!(cstr_from_pstr_oversized.into_owned(), cstr_from_string_oversized);
    }
}
<|endoftext|>


<commit_before>pub mod newc;

pub use newc::Builder as NewcBuilder;
<commit_msg>utility function to write out a vec of files as a CPIO archive<commit_after>use std::io;

pub mod newc;
pub use newc::Builder as NewcBuilder;

pub fn write_cpio<RS, W>(mut inputs: Vec<(NewcBuilder, RS)>, output: W) -> io::Result<W>
    where RS: io::Read + io::Seek,
          W: io::Write
{
    let output = try!(inputs.drain(..)
        .enumerate()
        .fold(Ok(output), |output, (idx, (builder, mut input))| {

            // If the output is valid, try to write the next input file
            output.and_then(move |output| {

                // Grab the length of the input file
                let len = try!(input.seek(io::SeekFrom::End(0)));
                try!(input.seek(io::SeekFrom::Start(0)));

                // Create our writer fp with a unique inode number
                let mut fp = builder.ino(idx as u32)
                    .write(output, len as u32);

                // Write out the file
                try!(io::copy(&mut input, &mut fp));

                // And finish off the input file
                fp.finish()
            })
        }));

    newc::trailer(output)
}

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

    #[test]
    fn test_multi_file() {
        // Set up our input files
        let input = vec![
            (NewcBuilder::new("./hello_world")
                .uid(1000)
                .gid(1000)
                .mode(0o100644), Cursor::new("Hello, World".to_string())),
            (NewcBuilder::new("./hello_world2")
                .uid(1000)
                .gid(1000)
                .mode(0o100644), Cursor::new("Hello, World 2".to_string())),
        ];

        // Set up our output file
        let output = Cursor::new(vec![]);

        // Write out the CPIO archive
        let _ = write_cpio(input, output).unwrap();
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A SDL2 window back-end for the Piston game engine.

extern crate sdl2;
extern crate window;
extern crate shader_version;
extern crate input;
extern crate gl;
extern crate current;

// External crates.
use std::mem::transmute;
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, ExitOnEsc
};
use input::{ keyboard, Button, MouseButton, Input, Motion };
use shader_version::opengl::OpenGL;
use current::{ ActOn, Action, GetFrom, SetAt, Set };

/// A widow implemented by SDL2 back-end.
pub struct Sdl2Window {
    /// SDL window handle
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    exit_on_esc: bool,
}

#[test]
fn test_sdl2_window() {
    fn foo<T: Window>() {}

    foo::<Sdl2Window>();
}

impl Sdl2Window {
    /// Creates a new game window for SDL2.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> Sdl2Window {
        sdl2::init(sdl2::INIT_EVERYTHING);
        let (major, minor) = opengl.get_major_minor();
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextMajorVersion,
            major
        );
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextMinorVersion,
            minor
        );
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextProfileMask,
            sdl2::video::GLProfile::GLCoreProfile as int
        );
        if settings.samples != 0 {
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLMultiSampleBuffers,
                1
            );
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLMultiSampleSamples,
                settings.samples as int
            );
        }

        let window = sdl2::video::Window::new(
            settings.title.as_slice(),
            sdl2::video::WindowPos::PosCentered,
            sdl2::video::WindowPos::PosCentered,
            settings.size[0] as int,
            settings.size[1] as int,
            sdl2::video::OPENGL| sdl2::video::RESIZABLE
        ).unwrap();
        if settings.fullscreen {
            window.set_fullscreen(sdl2::video::FullscreenType::FTTrue);
        }

        // Send text input events.
        sdl2::keyboard::start_text_input();

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers
        gl::load_with(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });

        Sdl2Window {
            exit_on_esc: settings.exit_on_esc,
            should_close: false,
            window: window,
            context: context,
            mouse_relative: None,
        }
    }
}

impl Drop for Sdl2Window {
    fn drop(&mut self) {
        self.set_mut(CaptureCursor(false));
    }
}

impl GetFrom<Sdl2Window> for ShouldClose {
    fn get_from(obj: &Sdl2Window) -> ShouldClose {
        ShouldClose(obj.should_close)
    }
}

impl GetFrom<Sdl2Window> for Size {
    fn get_from(obj: &Sdl2Window) -> Size {
        let (w, h) = obj.window.get_size();
        Size([w as u32, h as u32])
    }
}

impl ActOn<Sdl2Window, ()> for SwapBuffers {
    fn act_on(self, window: &mut Sdl2Window) {
        window.window.gl_swap_window();
    }
}

impl ActOn<Sdl2Window, Option<Input>> for PollEvent {
    fn act_on(self, window: &mut Sdl2Window) -> Option<Input> {
        match window.mouse_relative {
            Some((x, y)) => {
                window.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }
        match sdl2::event::poll_event() {
            sdl2::event::Event::Quit(_) => {
                window.should_close = true;
            }
            sdl2::event::Event::TextInput(_, _, text) => {
                return Some(Input::Text(text));
            }
            sdl2::event::Event::KeyDown(_, _, key, _, _, repeat) => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                if repeat {
                    return window.action(PollEvent)
                }

                if window.exit_on_esc
                && key == sdl2::keycode::KeyCode::Escape {
                    window.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(sdl2_map_key(key))));
                }
            }
            sdl2::event::Event::KeyUp(_, _, key, _, _, repeat) => {
                if repeat {
                    return window.action(PollEvent)
                }
                return Some(Input::Release(Button::Keyboard(sdl2_map_key(key))));
            }
            sdl2::event::Event::MouseButtonDown(_, _, _, button, _, _) => {
                return Some(Input::Press(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseButtonUp(_, _, _, button, _, _) => {
                return Some(Input::Release(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseMotion(_, _, _, _, x, y, dx, dy) => {
                // Send relative move movement next time.
                window.mouse_relative = Some((dx as f64, dy as f64));
                return Some(Input::Move(Motion::MouseCursor(x as f64, y as f64)));
            },
            sdl2::event::Event::MouseWheel(_, _, _, x, y) => {
                return Some(Input::Move(Motion::MouseScroll(x as f64, y as f64)));
            }
            sdl2::event::Event::Window(_, _, sdl2::event::WindowEventId::Resized, w, h) => {
                return Some(Input::Resize(w as u32, h as u32));
            }
            sdl2::event::Event::Window(_, _, sdl2::event::WindowEventId::FocusGained, _, _) => {
                return Some(Input::Focus(true));
            }
            sdl2::event::Event::Window(_, _, sdl2::event::WindowEventId::FocusLost, _, _) => {
                return Some(Input::Focus(false));
            }
            _ => {}
        }
        None
    }
}

impl SetAt<Sdl2Window> for CaptureCursor {
    fn set_at(self, _window: &mut Sdl2Window) {
        let CaptureCursor(enabled) = self;
        sdl2::mouse::set_relative_mouse_mode(enabled)
    }
}

impl SetAt<Sdl2Window> for ShouldClose {
    fn set_at(self, window: &mut Sdl2Window) {
        let ShouldClose(val) = self;
        window.should_close = val;
    }
}

impl GetFrom<Sdl2Window> for DrawSize {
    fn get_from(obj: &Sdl2Window) -> DrawSize {
        let (w, h) = obj.window.get_drawable_size();
        DrawSize([w as u32, h as u32])
    }
}

impl GetFrom<Sdl2Window> for Title {
    fn get_from(obj: &Sdl2Window) -> Title {
        Title(obj.window.get_title())
    }
}

impl SetAt<Sdl2Window> for Title {
    fn set_at(self, window: &mut Sdl2Window) {
        let Title(val) = self;
        window.window.set_title(val.as_slice());
    }
}

impl GetFrom<Sdl2Window> for ExitOnEsc {
    fn get_from(obj: &Sdl2Window) -> ExitOnEsc {
        ExitOnEsc(obj.exit_on_esc)
    }
}

impl SetAt<Sdl2Window> for ExitOnEsc {
    fn set_at(self, window: &mut Sdl2Window) {
        let ExitOnEsc(val) = self;
        window.exit_on_esc = val;
    }
}

/// Maps a SDL2 key to piston-input key.
pub fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use std::num::FromPrimitive;
    FromPrimitive::from_u64(keycode as u64).unwrap()
}

/// Maps a SDL2 mouse button to piston-input button.
pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> MouseButton {
    match button {
        sdl2::mouse::Mouse::Left => MouseButton::Left,
        sdl2::mouse::Mouse::Right => MouseButton::Right,
        sdl2::mouse::Mouse::Middle => MouseButton::Middle,
        sdl2::mouse::Mouse::X1 => MouseButton::X1,
        sdl2::mouse::Mouse::X2 => MouseButton::X2,
        sdl2::mouse::Mouse::Unknown(_) => MouseButton::Unknown,
    }
}
<commit_msg>Removed unnecessary unit test<commit_after>#![deny(missing_docs)]

//! A SDL2 window back-end for the Piston game engine.

extern crate sdl2;
extern crate window;
extern crate shader_version;
extern crate input;
extern crate gl;
extern crate current;

// External crates.
use std::mem::transmute;
use window::{
    WindowSettings,
    ShouldClose, Size, PollEvent, SwapBuffers,
    CaptureCursor, DrawSize, Title, ExitOnEsc
};
use input::{ keyboard, Button, MouseButton, Input, Motion };
use shader_version::opengl::OpenGL;
use current::{ ActOn, Action, GetFrom, SetAt, Set };

/// A widow implemented by SDL2 back-end.
pub struct Sdl2Window {
    /// SDL window handle
    pub window: sdl2::video::Window,
    /// Allow dead code because this keeps track of the OpenGL context.
    /// Will be released on drop.
    #[allow(dead_code)]
    pub context: sdl2::video::GLContext,
    should_close: bool,
    mouse_relative: Option<(f64, f64)>,
    exit_on_esc: bool,
}

impl Sdl2Window {
    /// Creates a new game window for SDL2.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> Sdl2Window {
        sdl2::init(sdl2::INIT_EVERYTHING);
        let (major, minor) = opengl.get_major_minor();
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextMajorVersion,
            major
        );
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextMinorVersion,
            minor
        );
        sdl2::video::gl_set_attribute(
            sdl2::video::GLAttr::GLContextProfileMask,
            sdl2::video::GLProfile::GLCoreProfile as int
        );
        if settings.samples != 0 {
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLMultiSampleBuffers,
                1
            );
            sdl2::video::gl_set_attribute(
                sdl2::video::GLAttr::GLMultiSampleSamples,
                settings.samples as int
            );
        }

        let window = sdl2::video::Window::new(
            settings.title.as_slice(),
            sdl2::video::WindowPos::PosCentered,
            sdl2::video::WindowPos::PosCentered,
            settings.size[0] as int,
            settings.size[1] as int,
            sdl2::video::OPENGL| sdl2::video::RESIZABLE
        ).unwrap();
        if settings.fullscreen {
            window.set_fullscreen(sdl2::video::FullscreenType::FTTrue);
        }

        // Send text input events.
        sdl2::keyboard::start_text_input();

        let context = window.gl_create_context().unwrap();

        // Load the OpenGL function pointers
        gl::load_with(|s| unsafe {
            transmute(sdl2::video::gl_get_proc_address(s))
        });

        Sdl2Window {
            exit_on_esc: settings.exit_on_esc,
            should_close: false,
            window: window,
            context: context,
            mouse_relative: None,
        }
    }
}

impl Drop for Sdl2Window {
    fn drop(&mut self) {
        self.set_mut(CaptureCursor(false));
    }
}

impl GetFrom<Sdl2Window> for ShouldClose {
    fn get_from(obj: &Sdl2Window) -> ShouldClose {
        ShouldClose(obj.should_close)
    }
}

impl GetFrom<Sdl2Window> for Size {
    fn get_from(obj: &Sdl2Window) -> Size {
        let (w, h) = obj.window.get_size();
        Size([w as u32, h as u32])
    }
}

impl ActOn<Sdl2Window, ()> for SwapBuffers {
    fn act_on(self, window: &mut Sdl2Window) {
        window.window.gl_swap_window();
    }
}

impl ActOn<Sdl2Window, Option<Input>> for PollEvent {
    fn act_on(self, window: &mut Sdl2Window) -> Option<Input> {
        match window.mouse_relative {
            Some((x, y)) => {
                window.mouse_relative = None;
                return Some(Input::Move(Motion::MouseRelative(x, y)));
            }
            None => {}
        }
        match sdl2::event::poll_event() {
            sdl2::event::Event::Quit(_) => {
                window.should_close = true;
            }
            sdl2::event::Event::TextInput(_, _, text) => {
                return Some(Input::Text(text));
            }
            sdl2::event::Event::KeyDown(_, _, key, _, _, repeat) => {
                // SDL2 repeats the key down event.
                // If the event is the same as last one, ignore it.
                if repeat {
                    return window.action(PollEvent)
                }

                if window.exit_on_esc
                && key == sdl2::keycode::KeyCode::Escape {
                    window.should_close = true;
                } else {
                    return Some(Input::Press(Button::Keyboard(sdl2_map_key(key))));
                }
            }
            sdl2::event::Event::KeyUp(_, _, key, _, _, repeat) => {
                if repeat {
                    return window.action(PollEvent)
                }
                return Some(Input::Release(Button::Keyboard(sdl2_map_key(key))));
            }
            sdl2::event::Event::MouseButtonDown(_, _, _, button, _, _) => {
                return Some(Input::Press(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseButtonUp(_, _, _, button, _, _) => {
                return Some(Input::Release(Button::Mouse(sdl2_map_mouse(button))));
            }
            sdl2::event::Event::MouseMotion(_, _, _, _, x, y, dx, dy) => {
                // Send relative move movement next time.
                window.mouse_relative = Some((dx as f64, dy as f64));
                return Some(Input::Move(Motion::MouseCursor(x as f64, y as f64)));
            },
            sdl2::event::Event::MouseWheel(_, _, _, x, y) => {
                return Some(Input::Move(Motion::MouseScroll(x as f64, y as f64)));
            }
            sdl2::event::Event::Window(_, _, sdl2::event::WindowEventId::Resized, w, h) => {
                return Some(Input::Resize(w as u32, h as u32));
            }
            sdl2::event::Event::Window(_, _, sdl2::event::WindowEventId::FocusGained, _, _) => {
                return Some(Input::Focus(true));
            }
            sdl2::event::Event::Window(_, _, sdl2::event::WindowEventId::FocusLost, _, _) => {
                return Some(Input::Focus(false));
            }
            _ => {}
        }
        None
    }
}

impl SetAt<Sdl2Window> for CaptureCursor {
    fn set_at(self, _window: &mut Sdl2Window) {
        let CaptureCursor(enabled) = self;
        sdl2::mouse::set_relative_mouse_mode(enabled)
    }
}

impl SetAt<Sdl2Window> for ShouldClose {
    fn set_at(self, window: &mut Sdl2Window) {
        let ShouldClose(val) = self;
        window.should_close = val;
    }
}

impl GetFrom<Sdl2Window> for DrawSize {
    fn get_from(obj: &Sdl2Window) -> DrawSize {
        let (w, h) = obj.window.get_drawable_size();
        DrawSize([w as u32, h as u32])
    }
}

impl GetFrom<Sdl2Window> for Title {
    fn get_from(obj: &Sdl2Window) -> Title {
        Title(obj.window.get_title())
    }
}

impl SetAt<Sdl2Window> for Title {
    fn set_at(self, window: &mut Sdl2Window) {
        let Title(val) = self;
        window.window.set_title(val.as_slice());
    }
}

impl GetFrom<Sdl2Window> for ExitOnEsc {
    fn get_from(obj: &Sdl2Window) -> ExitOnEsc {
        ExitOnEsc(obj.exit_on_esc)
    }
}

impl SetAt<Sdl2Window> for ExitOnEsc {
    fn set_at(self, window: &mut Sdl2Window) {
        let ExitOnEsc(val) = self;
        window.exit_on_esc = val;
    }
}

/// Maps a SDL2 key to piston-input key.
pub fn sdl2_map_key(keycode: sdl2::keycode::KeyCode) -> keyboard::Key {
    use std::num::FromPrimitive;
    FromPrimitive::from_u64(keycode as u64).unwrap()
}

/// Maps a SDL2 mouse button to piston-input button.
pub fn sdl2_map_mouse(button: sdl2::mouse::Mouse) -> MouseButton {
    match button {
        sdl2::mouse::Mouse::Left => MouseButton::Left,
        sdl2::mouse::Mouse::Right => MouseButton::Right,
        sdl2::mouse::Mouse::Middle => MouseButton::Middle,
        sdl2::mouse::Mouse::X1 => MouseButton::X1,
        sdl2::mouse::Mouse::X2 => MouseButton::X2,
        sdl2::mouse::Mouse::Unknown(_) => MouseButton::Unknown,
    }
}
<|endoftext|>